如何忽略延迟返回的旧AJAX数据,优先处理最新请求响应?
如何处理AJAX乱序返回:忽略更早发起但延迟返回的旧响应
问题背景
日常前端开发中经常会遇到AJAX响应乱序返回的问题:
- 12:01:33 第一次发起数据请求,因为网络链路延迟,直到12:01:39才返回响应
- 12:01:36 用户触发第二次数据请求,反而在12:01:38就完成了响应返回
这种时序下,12:01:39返回的第一次请求的旧数据绝对不能被采纳,否则会直接覆盖第二次请求已经渲染完成的正确结果。
常见适用场景
按钮类交互我们通常可以通过点击后置灰禁用按钮的方式避免重复触发,但文本输入类的场景根本无法靠禁用交互解决:
比如搜索框中,用户先输入“React”按下回车触发搜索,接着又补充输入“ Redux”再次按下回车触发第二次搜索。这种场景下不管第一次请求是在第二次之前还是之后返回,都必须完全忽略“React”对应的旧搜索结果,仅采纳并渲染最新的“React Redux”对应的搜索结果。
常规实现思路:时间戳校验方案
最容易想到的实现方式是基于时间戳的合法性校验:
let fetchTimeStampToHonor; function getData() { // 为本次请求生成独有的时间标识 const currentFetchTimestamp = Date.now(); // 每次发起新请求,就把全局合法校验值更新为最新的时间戳 fetchTimeStampToHonor = currentFetchTimestamp; fetch("...") .then(res => res.json()) .then(data => { // 仅当本次请求的时间戳和当前全局合法值一致时,才采纳该响应 if (currentFetchTimestamp === fetchTimeStampToHonor) { // 处理合法响应数据 } }); }
这套逻辑的原理是利用JS闭包的特性:每个.then的回调函数都能访问到本次请求发起时存的局部时间戳currentFetchTimestamp,只要校验这个值和当前全局存的最新合法值匹配,就说明这是最新请求的响应,没有被后续的新请求取代。
原始实现中的全局变量存在作用域污染的风险,实际落地可以做几个适配优化:
- 通过闭包将
fetchTimeStampToHonor封装在私有作用域内,避免全局暴露 - 放在ES模块作用域中,变量仅对模块内部可见,不会污染全局环境
- 如果是React项目,可将校验值存在组件的ref中,和组件生命周期绑定,组件卸载时自动释放,避免内存泄漏
延伸讨论
除了时间戳校验的实现思路,是否有更稳妥、更工程化的优化方案?
内容的提问来源于stack exchange,提问作者nonopolarity
相关产品推荐
相关产品推荐

