问题背景
最近在用 uni-app
开发前端收银台页面,遇到一个问题:用户输入支付金额时,需要通过后台请求进行实时计价。如果用户快速连续输入金额,由于请求接口响应速度不同,可能先请求的接口后响应,导致计价显示错误。如用户快速输入 300 元时,可能最终看到的是 30 元的计价结果,这种情况是要不得的。那么我们应该如何解决?
解决方法
要解决上面的问题,就需要在每次发起新的计价请求时,取消或终止上一次未响应的请求。
uni.request
如果使用的是 uni.request
发起网络请求的。通过传入 success / fail / complete
中的一个或多个参数,即可返回一个 requestTask
对象。通过 requestTask.abort()
即可中断请求任务。这个比较简单,这边不做展开。
Promise
虽然说上述的 uni.request
方法,就可以实现网络请求和中断任务。但是实际使用中,为了实现请求的同步化,我们用的比较多的可能是对 uni.request
进行封装返回 Promise
(该部分内容请参考 之前的文章)。
之前在学习 Promise
的时候,看到的 Promise.race
(参见:JS 中 Promise 三剑客 Promise.all、Promise.race 和 Promise.allSettled)刚好可以派上用场。
顾名思义,Promise.race
是赛跑的意思,Promise.race 中的 Promise 数组中谁先返回成功或失败的结果,整体就返回那个结果。我们可以在下一次请求之前,通过 reject
模拟请求失败,结合 Promise.race
的“赛跑”功能,实现上次请求如未成功则直接失败处理,如果成功,则正常返回。具体代码如下:
实现方式:
以下代码根据实际情况,可放在页面组件或自己项目的公共函数库中。
createPromiseWithAbort(fetchPromise) { // 创建一个可终止的 Promise 对象
let abort = null
const abortPromise = new Promise((resolve, reject) => {
abort = () => reject('abort')
})
let promiseWithAbort = Promise.race([fetchPromise, abortPromise])
promiseWithAbort.abort = abort
return promiseWithAbort
},
abortPromise(promiseWithAbort) { // 终止未完成的 Promise 对象 promiseWithAbort
if (promiseWithAbort != null && promiseWithAbort.abort) {
promiseWithAbort.abort()
}
}
使用方式:
import http from '@/commons/http.js'
export default {
data() {
return {
payDiscountPromise: null
}
},
methods: {
calculate() {
// 终止未完成的 payDiscountPromise 请求
this.$util.abortPromise(this.payDiscountPromise)
// 计价 Promise 请求
let doPricePromise = http('data/get1', {
param: {
}
})
// 返回可终止的 Promise 对象
this.payDiscountPromise = this.$util.createPromiseWithAbort(doPricePromise)
// 对计价结果进行处理,如果下次请求之前调用了 promiseAbort 且请求未完成将被终止
this.payDiscountPromise.then(res => {
}).catch(err => {
console.error(err)
})
}
}
}
版权属于:瞭月
本文链接:https://www.lervor.com/archives/189/
版权声明:本文为瞭月原创文章,转载请附上原文出处链接和本声明。
6 条评论
Cannot read property 'abortPromise' of undefined 放到公共函数里.调用时候会这样呢.
是使用的时候 this.$util.abortPromise 这个报的吗,如果是的话,看看把 this.$util 换成自己存放 abortPromise 的js文件或函数库里
可以用防抖来解决这个问题?
可以,当前场景下防抖方式更好
这方法不错,简单易用~~