• 作者:老汪软件技巧
  • 发表时间:2024-08-31 17:01
  • 浏览量:

发现问题

前端开发中,有一个很常见的问题:如何在多次请求中,正确地处理响应数据和原始请求保持一致。说起来有点拗口,我这里直接用一个简洁明了的例子来讲解。假如要写一个可分页的表格页面,它的原始代码如下:



以上代码很好理解,它潜在的问题是:如果当前在第1页,用户点击第2页,又在接口pending的时候点了第3页,好巧不巧,后端在响应第2页的时候卡了几秒才返回,但在响应第3页是秒返回的。在前端体现就是明明在第3页,显示的却是第2页的数据。

两个方案

方案1不够优雅,我们这里考虑如何实现方案2。

实现

废话不多说,直接端上代码,主要用到的是闭包以及#axios取消请求:

export const useAbortController = extends Array<unknown>, R = any>(fn: (controller?: AbortController, ...args: T) => Promise>) => {
  // 在闭包里存一个 AbortController
  let controller: AbortController | undefined
  return (...args: T) => {
    // 取消上一个请求(如果有的话)
    if (controller) {
      controller.abort();
    }
    // 重新创建一个 AbortController,并传给实际要调的函数
    controller = new AbortController()
    return fn(controller, ...args)
  }
}

有了上面的功能函数,之前的代码可做如下修改:



以上可以完美实现响应数据和原始请求保持一致,简单实用。

感谢你的阅读

文章来自于我的个人博客:vue3用于管理axios异步请求一致性的功能函数 - yunyuyuan blog

插曲

以前写Angular的时候,用rxjs的switchMap可以轻松达到该目的

const rows = ref<{id: number, name: string, age: number}[]>([])
const currentPage = ref(1)
const total = ref(0)
const requestSubject = new Subject();
// 订阅 requestSubject,通过 switchMap 实现请求的切换
const subscription = requestSubject.pipe(
    switchMap(() => {
        // 将 axios 请求包装成 observable
        return from(axios.get(`/api/list?page=${currentPage.value}`)).pipe(
            catchError((error) => {
                return [];
            })
        );
    })
).subscribe(res => {
    rows.value = res.data.list
    total.value = res.data.total
});
const getList = () => {
    // 每次调用 getList 时,都会触发 switchMap 的操作
    requestSubject.next();
};

上面用switchMap只是简单地切换订阅请求,并不会中断上一个请求。


上一条查看详情 +数组去重之进阶版
下一条 查看详情 +没有了