You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript并发异步操作中setInterval与Promise执行逻辑验证问题

你的结论完全正确,这个现象由JavaScript单线程事件循环的执行规则决定,没有问题。

核心逻辑验证

JavaScript运行时是单线程的,所有同步代码、微任务、宏任务的执行遵循以下优先级:

  • 先执行当前调用栈的所有同步代码
  • 清空全部微任务队列
  • 再取宏任务队列的最早一个任务执行

两个setInterval注册的回调都属于宏任务,必须等当前执行上下文清空后才会被调度,不可能打断正在运行的同步代码。


第一个版本无报错的原因

你最初的b回调逻辑:

const b = setInterval(async () => {
  await new Promise(resolve => setTimeout(resolve, 500));
  total = [...total, ...buffer];
  buffer = [];
}, 1);

执行流程是:

  1. b的回调触发后,第一行遇到await,直接让出线程,此时a的回调可以正常被调度,持续往buffer里push递增的count值
  2. 500ms后await后的逻辑被推入微任务队列,此时引擎会先清空微任务再处理下一个宏任务:
    • total = [...total, ...buffer]和buffer = []是连续的同步代码,执行过程中不会被a的宏任务打断
    • 没有新的count会在拷贝和清空buffer的间隙被push进buffer,因此total里的数值完全连续,不会出现不匹配的报错

修改后出现报错的原因

你调整后的b回调逻辑:

const b = setInterval(async () => {
  total = [...total, ...buffer];
  await new Promise(resolve => setTimeout(resolve, 500));
  buffer = [];
}, 1);

执行流程出现了断层:

  1. b的回调触发后,先同步把当前buffer的内容拷贝到total,然后才遇到await让出线程
  2. 接下来的500ms里,a的回调持续往buffer里push新的count值,这些值没有被拷贝到total
  3. 500ms后执行buffer = [],直接清空了这500ms里新增的未被记录的count值,导致total里的数值出现断档,自然会触发Error on x的日志,刚好反向验证了你之前的结论。

内容的提问来源于stack exchange,提问作者Corentin Bernard

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 00:54:02