这是前端面试里几乎必考的一题,很多人都会答错。
🧨 面试官问题
setTimeout(fn, 0)会不会立即执行?- 为什么不能立即执行?
- 浏览器中最短延迟是多少?
- Node.js 中的延迟规则是否不同?
🧩 标准答案
❌ 不会立即执行。
即使你写:
javascript
setTimeout(() => console.log("A"), 0)
也不会马上执行,因为它属于 宏任务(MacroTask)。
🔍 为什么不会立即执行?
原因 1:setTimeout 是宏任务,必须等待当前执行栈和所有微任务清空
事件循环顺序:
同步代码 → 微任务队列全部执行 → 宏任务队列
所以即使 delay=0,也要等:
- 当前同步代码执行完
- 微任务(Promise.then 等)全部执行完
- 才轮到 setTimeout 的回调
宏任务永远排在微任务之后
原因 2:浏览器有最小时间限制(最短延迟)
📌 历史最短延迟:4ms(HTML5 规范)
浏览器规定:
重复使用 setTimeout 的最小延迟是 4ms。
(避免性能问题和高 CPU 占用)
Chrome/Firefox/Safari 都遵守。
但是:
如果是第一次调用 setTimeout,则允许 0ms。
但仍然不会立即执行,因为事件循环机制会延迟它。
🎯 结论:setTimeout(fn, 0) 的实际执行时机
- 不是立即
- 不是 0ms 后
- 而是在下一轮宏任务队列中执行
📌 对比不同环境:浏览器 vs Node.js
🖥 浏览器
- 多次使用时,最小延迟会被强制提升到 4ms
- Promise → 微任务
- timeout → 宏任务
🟩 Node.js
Node.js 中:
javascript
setTimeout(fn, 0)
实际延迟 接近 1ms 左右,但完全取决于:
- 事件循环阶段 (timers phase)
- 系统时间精度
- 负载情况
Node.js 不遵守浏览器 4ms 的限制。
✔ 小测试(加深理解)
猜输出:
javascript
console.log(1)
setTimeout(() => console.log(2), 0)
Promise.resolve().then(() => console.log(3))
console.log(4)
正确输出:
1
4
3
2
- 微任务优先于宏任务
- 即便是 setTimeout 0,也排在 Promise.then 后面
🧠 速记卡
🔶 速记:setTimeout(fn, 0) 永远不会立即执行
- 因为它是宏任务
🔶 速记:执行顺序
同步 → 微任务 → 宏任务(setTimeout)