在React类组件中,经常需要在componentDidUpdate、componentWillReceiveProps判断各种属性的变化触发某个请求,在Vue中也经常会用一个watch监听若干变量,触发某个请求
在这些情况当中,请求通常会并行触发很多次,但发出去的请求是不是按照顺序回来,就无法保证了,因此回调执行的顺序就会出现问题,通常情况下我们需要的是最新的那次回调回来的数据
可以通过闭包的方式,为每次函数的调用创建一个变量,建立起一个对应的关联关系来
方法一:
class CustomForm {
...
componentDidUpdate = (prevProps) => {
if (prevProps.initialValues.nid !== this.props.initialValues.nid) {
// fetchMetrics可能会请求多次
this.fetchMetrics(0)
}
}
...
// 在较高一级作用域上添加一个变量,用来跟踪最新走到了第几次
CustomForm.fetchMetricsExceTimes = 0
async fetchMetrics(category = 1, value) {
// 每调用一次fetchMetrics,就将全局变量加1
CustomForm.fetchMetricsExceTimes++
// 同时,新建一个局部变量,来和本次调用形成映射关系
let curFetchMetricsExecIndex = CustomForm.fetchMetricsExceTimes
// 进行了一些异步操作
await xxx
// 每次请求回来的顺序可能不同,如果满足下面的条件,则证明先发出去的请求后回来了,直接忽略,避免走到下面的setState,将错误的数据展示到页面
if (curFetchMetricsExecIndex < CustomForm.fetchMetricsExceTimes) return
// 将正确的数据设置上去
this.setState({ metrics });
方法二:
在每一次触发请求时,都打一个标记,标记这次这次请求的结果应不应该用来更新页面,每次请求进来时都将上次发起的请求对应的标记置为false:
class CustomForm {
...
componentDidUpdate = (prevProps) => {
if (prevProps.initialValues.nid !== this.props.initialValues.nid) {
// fetchMetrics可能会请求多次
this.fetchMetrics(0)
}
}
...
// 用来存放本次请求结果应不应该用来更新页面的标记设置方法
CustomForm.arr = []
async fetchMetrics(category = 1, value) {
while (CustomForm.arr.length > 0) {
let fn = CustomForm.arr.shift();
fn();
}
let shouldUseResponse = true;
CustomForm.arr.push(function () {
shouldUseResponse = false
})
// 进行了一些异步操作
await xxx
// 只有最后一次的shouldUseResponse为true,这次对应的结果也正是我们想要的,因此将正确的数据设置上去即可
shouldUseResponse && this.setState({ metrics });
对于构成闭包的函数,其定义时所处的作用域和执行时所处的作用域不同