setTimeout何时开始倒计时?异步执行与定时器触发顺序疑问
setTimeout执行顺序疑问
调试代码
setTimeout(() => console.log('first'), 2000); for (let i = 0; i < 5000; i++) { console.log("printing...") } setTimeout(() => console.log('second'), 1000);
预期执行逻辑(认为setTimeout立即开始倒计时)
- 第一个setTimeout执行并启动2000ms定时器,由于其回调为异步执行,需等待调用栈清空后才会进入回调队列。
- 执行for循环,在我的设备上耗时约20秒,期间第一个setTimeout的定时器应已完成倒计时。
- 第二个setTimeout执行并启动1000ms定时器,逻辑同第一步。
- 调用栈清空后处理回调队列,因第一个setTimeout先完成倒计时,应先输出'first'再输出'second'。
实际执行结果
printing... /* 大量"printing..."输出 */ printing... second first
问题解答
不是的,setTimeout的定时器是在调用setTimeout函数的那一刻就开始计时,而非等初始代码执行完成后才启动。
你看到的结果核心原因是:你的for循环实际耗时远小于你估算的20秒(大概率是估算误差)。举个具体例子,假设for循环实际仅耗时0.5秒:
- 第0秒:调用第一个setTimeout,启动2000ms定时器(将在第2秒到期)。
- 第0-0.5秒:执行for循环,输出所有"printing..."。
- 第0.5秒:调用第二个setTimeout,启动1000ms定时器(将在第1.5秒到期)。
- 第0.5秒后:初始代码执行完毕,调用栈清空,事件循环开始等待任务。
- 第1.5秒:第二个定时器到期,其回调被加入宏任务队列,事件循环处理它,输出"second"。
- 第2秒:第一个定时器到期,其回调被加入宏任务队列,事件循环处理它,输出"first"。
如果for循环真的耗时20秒,那第一个定时器会在第2秒就到期,回调进入宏任务队列等待。等20秒后for循环结束,调用第二个setTimeout启动1000ms定时器,此时调用栈清空,事件循环会先处理队列里已有的第一个回调,输出"first",然后等1秒后再处理第二个回调输出"second",结果就会和你的预期一致。
你可以给for循环加个计时验证实际耗时:
console.time('loop'); for (let i = 0; i < 5000; i++) { console.log("printing...") } console.timeEnd('loop');
内容的提问来源于stack exchange,提问作者seeingstars
相关产品推荐
相关产品推荐

