- 作者:老汪软件技巧
- 发表时间:2024-08-31 17:01
- 浏览量:
发现问题
在前端开发中,有一个很常见的问题:如何在多次请求中,正确地处理响应数据和原始请求保持一致。说起来有点拗口,我这里直接用一个简洁明了的例子来讲解。假如要写一个可分页的表格页面,它的原始代码如下:
id
name
age
{{ item.id }}
{{ item.name }}
{{ item.age }}
以上代码很好理解,它潜在的问题是:如果当前在第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只是简单地切换订阅请求,并不会中断上一个请求。