分析以下一个场景,有一个select下拉框,下拉数据来源于用户输入的值并通过接口查询进行远程加载。假设用户输入1之后,接口需要5s才能得到响应值。用户输入2之后接口只需要1s就能得到响应值。用户先输入1,然后触发了第一次查询,接着删掉输入2,触发了第二次查询。这个时候会出现一个奇怪的现象。下拉数据先渲染条件为2的数据,接着在渲染条件为1的数据,造成了数据混乱。
以上场景不止在这个特殊场景下存在,当遇到网络不好的时候,也会出现这个问题。并且就算给这些频繁操作的接口加上防抖也无法彻底避免这个问题。
临时解决办法:限制同类型的请求,当同类型的请求未完成之前不允许发送第二次请求,比如加上loading或者disabled来限制同类型的操作。
真正的解决办法:①取消请求。利用Cancel Token或者AbortController,当第二次请求数据接口时,取消第一次的请求。②id查询。每次向后台进行数据请求时带上唯一的id,在渲染时通过id来选择数据进行渲染。③前端闭包记录每次请求的id,渲染时通过id来选择数据进行渲染。
第三种方案的简易实现如下:
const cache = {};
const asyncDebounce = (key) => {
const time = new Date().getTime();
cache[key] = time;
return () => cache[key] === time;
};
使用方法:
function test(p){
// 同一数据接口的key,可以使用url来作为key
const isValid = asyncDebounce('test');
const result = new Promise((resolve) => setTimeout(() => resolve(p),3000));
result.then(res => {
if(isValid()){
// 只会拿到最后一次的数据
}
})
}
test('请求一');
test('请求二');
test('请求三');