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

为何setTimeout执行顺序不符合预期?JS异步机制疑问

为什么这段JavaScript代码的输出顺序是2、3、1?

代码示例

setTimeout(() => console.log("1"), 1000)

const startTime = Date.now()
while (Date.now() - startTime < 5000);

setTimeout(() => console.log("2"), 0)
setTimeout(() => console.log("3"), 0)

实际输出

2
3
1

原因解析

核心在于JavaScript的单线程事件循环机制,以及setTimeout的任务调度逻辑:

  • 首先执行同步代码:

    • 调用第一个setTimeout后,浏览器会记录“1秒后将这个回调加入宏任务队列”,但此时主线程继续往下走,进入了while循环。
    • 这个while循环直接阻塞主线程5秒——因为JS是单线程,只要同步代码没执行完,事件循环就完全没机会处理任何异步任务,包括检查定时器是否到期。
  • 5秒后while循环结束,主线程终于有空处理后续逻辑:

    • 这时候第一个setTimeout的1秒早就到了,但浏览器之前根本没机会把它的回调放进宏任务队列——只有主线程空闲时,浏览器才会扫描到期的定时器,把对应的回调加入队列。
    • 紧接着执行后面两个setTimeout,它们的延迟是0,浏览器会立刻把这两个回调按顺序加入宏任务队列(先2后3)。
  • 当所有同步代码执行完毕,主线程开始处理宏任务队列:

    • 队列里的顺序是「2的回调 → 3的回调 → 1的回调」(1的回调是在这之后才被浏览器检测到到期并加入队列的)。
    • 因此会依次输出2、3,最后才是1。

总结:定时器到期只是获得了“排队资格”,但必须等主线程空闲,浏览器才会把它的回调放进任务队列;后面两个setTimeout是在主线程空闲前就被调度入队,所以排在了第一个定时器回调的前面。

内容的提问来源于stack exchange,提问作者Vadim Sheremetov

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 02:32:34