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

为何setTimeout延迟0仍在for循环同步代码后执行?

为什么setTimeout延迟设为0仍会出现这种运行行为?

我了解这类问题已有相关讨论,但我认为本次问题具有独特性。为何将延迟设置为0时,仍会出现如下运行行为?

代码示例

for(var i = 0; i <3; i ++) { 
  console.log(i, 'started'); 
  setTimeout(()=> { 
    console.log(i); 
  },0) 
  console.log(i, 'done'); 
} 
console.log('loop over');

输出结果

// 0 started 
// 0 done 
// 1 started 
// 1 done 
// 2 started 
// 2 done 
// loop over 
// 3 3 3

咱们把这个问题拆解开一步步看:

首先,JavaScript是单线程的,它必须先把当前调用栈里的所有同步任务执行完毕,才会去处理任务队列里的异步任务——这就是核心原因。

你这里用var声明变量i,var是函数/全局作用域,整个循环里的i其实是同一个全局变量。而setTimeout的回调函数属于异步任务,哪怕你把延迟设为0,它也不会立刻执行,而是会被放进任务队列排队,必须等当前所有同步代码(整个for循环+最后的console.log('loop over'))全部跑完,才会被取出执行。

等同步代码执行完成时,for循环已经终止了:最后一次循环i=2,执行i++后变成3,不再满足i<3的条件,所以此时i的值固定为3。这时候任务队列里的三个setTimeout回调才开始依次执行,它们引用的都是同一个全局i,自然都会输出3。

对应你提到的MDN逻辑:

这是因为setTimeout()的回调会被加入到任务队列,只有当调用栈为空时,才会从任务队列中取出任务执行。哪怕延迟设为0,也只是表示“尽可能快地执行”,但必须等当前同步任务全部完成。

另外,如果想让每个回调输出对应的循环值,只需要把var换成let就行——let是块级作用域,每次循环都会创建一个独立的i变量,回调函数会绑定当前循环的那个i,最后就会输出0、1、2了。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:16:24