搜索框里,最后返回的不一定是最新结果
搜索框有个很容易复现的问题:先输入“上海”,接着改成“杭州”。第二次请求可能先返回,页面先显示杭州;过一会儿,较慢的第一次请求返回,又把列表改回上海。用户看到的输入和列表就对不上了。
防抖解决不了返回顺序
防抖减少的是请求次数。只要两次请求都已经发出去,就仍然可能按相反顺序返回。我的习惯是给每次搜索分配一个递增编号,收到响应时只允许当前编号更新页面。
let latestRequest = 0;
async function search(keyword) {
const requestId = ++latestRequest;
loading = true;
errorMessage = '';
try {
const items = await fetchItems(keyword);
if (requestId === latestRequest) results = items;
} catch {
if (requestId === latestRequest) errorMessage = '搜索失败,请重试';
} finally {
if (requestId === latestRequest) loading = false;
}
}
上面是与框架无关的示意代码。错误提示和加载状态也要检查编号,否则旧请求虽然没有覆盖列表,却仍会提前关闭新请求的加载提示。
取消请求是另一件事
如果请求库支持取消,可以在新搜索开始时中止旧请求,减少无用传输。不过取消可能发生在响应已完成之后,也可能被中间的异步处理忽略,所以编号检查仍然保留。
清空输入时也要增加编号,再清空列表。否则之前发出的请求会在几秒后把结果重新填回来。页面离开时同理:取消请求,并让已有编号失效。
测试不用依赖真实的慢网络。准备两个可手动完成的 Promise,让第二个先成功、第一个后成功,就能稳定检查页面是否只保留第二次结果。