settimeout(fn, 0) 会将回调函数放入宏任务队列,并在当前同步代码执行完毕后、下一次渲染前由事件循环调度执行。具体做法是调用 settimeout 并传入零延迟,浏览器或 node.js 环境会将其注册为宏任务,等待主线程空闲后按顺序处理。

为什么零延迟不立即执行?
因为 JavaScript 采用单线程模型,所有同步代码必须优先完成。即使延迟设为 0,定时器机制也会将回调推迟到下一个宏任务阶段,确保当前调用栈清空。这是语言规范的设计,避免阻塞关键路径。

console.log('start');
setTimeout(() => console.log('timeout'), 0);
console.log('end');
预期输出:
start
end
timeout
不同环境下宏任务队列的行为差异
在浏览器中,setTimeout(fn, 0) 的回调进入宏任务队列,可能在下一帧渲染前执行;在 Node.js 中,它同样进入宏任务队列,但受 libuv 线程池影响,可能稍晚执行。两者都保证在当前同步代码之后运行。

// 浏览器环境示例
setTimeout(() => console.log('browser timeout'), 0);
// Node.js 环境示例
setTimeout(() => console.log('node timeout'), 0); // 注意:Node.js 中可能受其他 I/O 影响
预期输出(浏览器):
browser timeout
预期输出(Node.js):
node timeout(可能与其他 I/O 交错)
当多个 setTimeout(fn, 0) 同时存在时如何排序?
多个 setTimeout(fn, 0) 按注册顺序进入宏任务队列,依次执行。例如先注册的回调先执行,后注册的后执行。这符合 FIFO 原则,确保可预测的执行顺序。
setTimeout(() => console.log('first'), 0);
setTimeout(() => console.log('second'), 0);
预期输出:
first
second
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











