【发布时间】:2025-06-05 18:15:02
【问题描述】:
let state = 'A'
async function runTask() {
state = await someApi()
}
// `someApi`'s execution time may vary, as well as its response.
- 初始状态为
A,然后调用runTask。 - 出于某种原因,
runTask在上一次调用得到解决之前再次调用。 - 对
someApi的第二次调用以响应C解析,并相应更新状态。 - 对
someApi的第一次调用解析为响应B,并且相应地更新了状态,这是不可取的。
time state
| A
| A --- runTask
| A someApi(call #1)
| A |
| A |
| A ------------------------ runTask (get called before previous one settles)
| A | someApi(call #2)
| A | ‖
| A | ‖
| A | v
| C --------------------- response #2: C
| C |
| C |
| C v
| B -- response #1: B
| B
| B
v
我应该如何在javascript中优雅地解决这个问题?我能想到的一种解决方法是:为每个请求分配时间戳并维护一个全局 lastUpdated 变量,以防止任何过时和迟到的响应修改状态。但是,它感觉很脏并且不能很好地扩展,因为通常有很多状态和异步操作。
更新
赏金奖励最早的有利答案。
【问题讨论】:
-
对 XHR 处理程序的引用和取消令牌。
-
如果我们确实有正在运行的请求,我们可以延迟 someApi 吗?
-
"我应该如何在javascript中优雅地解决这个问题?" - 没有简单的解决方案(除了禁止
someApi()或runTask的并发调用,这实际上只是将问题一扫而光)。根本问题是您的程序正在覆盖(因此丢失)共享状态。我可能会建议您重构代码以类似于 Redux 模式... -
可以检查call id是否大于上一个结果。当响应 #1 到达时,它看到最后一个值是响应 #2 并忽略结果
标签: javascript asynchronous es6-promise race-condition cancellation