VueJS如何仅获取最后一次请求返回值 解决响应乱序问题
解决Vue中异步请求竞态导致响应式变量赋值错误的方案
你遇到的是典型的异步请求竞态问题:请求的响应返回顺序和发起顺序不一致,导致最终赋值的是旧请求的结果,而非最新请求的正确结果。可以通过以下几种方案解决:
方案1:添加请求标识,仅采用最新请求的返回结果
在组件内新增一个变量记录最新请求的标识,每次请求时更新标识,响应返回时仅当当前请求标识等于最新标识时才赋值:
// 组件内新增变量,不需要视图响应用普通变量即可 data() { return { // ...其他属性 latestRequestId: 0 } }, methods: { inputHandler(url, params){ // 每次发起请求更新最新请求ID const currentRequestId = ++this.latestRequestId const p = new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open('POST', url, true); // ...其余xhr原有逻辑 }); p.then(res => { // 仅当前请求是最新发起的请求时才赋值 if(currentRequestId === this.latestRequestId) { this.reactiveProperty = res } }); } }
方案2:取消上一次未完成的请求
每次发起新请求前,直接取消上一次还未返回的旧请求,从根源上避免旧请求返回后赋值的问题,同时还能节省不必要的带宽开销:
// 组件内存储上一次请求的xhr实例 data() { return { // ...其他属性 prevXhr: null } }, methods: { inputHandler(url, params){ // 发起新请求前先取消上一次未完成的请求 if(this.prevXhr) { this.prevXhr.abort() } const p = new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); // 把当前xhr实例存到组件变量中 this.prevXhr = xhr xhr.open('POST', url, true); // ...其余xhr原有逻辑,兼容手动abort的情况避免报错 xhr.onerror = () => { if(xhr.status === 0) return // 手动abort的情况不抛出错误 reject() } }); p.then(res => this.reactiveProperty = res); } }
方案3:添加防抖优化(适用于输入触发请求的场景)
如果是输入框输入过程中连续触发请求,可以先加300~500ms的防抖,等用户输入停止后再发起请求,减少无效请求的同时大幅降低竞态出现的概率,可配合上面两种方案使用:
// 简易防抖实现 const debounce = (fn, delay) => { let timer = null return function(...args) { clearTimeout(timer) timer = setTimeout(() => fn.apply(this, args), delay) } } // 把输入处理函数包装成防抖函数 methods: { inputHandler: debounce(function(url, params) { // 原有请求逻辑 }, 300) }
内容的提问来源于stack exchange,提问作者mark
相关产品推荐
相关产品推荐

