为什么setTimeout(fn, 0)不是立即执行?

慕容世杰 阅读 4

我在写一个表单验证的时候,想让某个提示信息在当前同步代码执行完后立刻显示,就用了setTimeout(() => { showTip() }, 0),但发现它居然比 Promise.then 还慢?这不符合我对“0毫秒延迟”的理解啊。

我试过把 delay 改成 1、10,甚至直接不写,结果都一样——总是在微任务之后才执行。难道 setTimeout 即使设成 0 也不会插队到当前任务中间?

下面是我测试的代码:

console.log('start');

setTimeout(() => {
  console.log('setTimeout');
}, 0);

Promise.resolve().then(() => {
  console.log('promise then');
});

console.log('end');

控制台输出顺序是:start → end → promise then → setTimeout。这到底是为啥?事件循环里宏任务和微任务到底怎么排的?

我来解答 赞 1 收藏
二维码
手机扫码查看
1 条解答
公孙圣哲
哈,这个老生常谈的问题了。setTimeout(fn,0)根本不是立即执行,它会把回调丢到宏任务队列,而Promise.then是微任务。事件循环总是先清空当前微任务队列才会执行下一个宏任务。

我一般直接记住这个顺序:同步代码 > 微任务 > 宏任务。所以你的代码里promise then永远比setTimeout先跑。

要立刻执行但又不想用Promise?可以试试这个骚操作:
queueMicrotask(() => {
console.log('这个比setTimeout快');
});


或者更懒就直接用Promise.resolve().then(),虽然有点丑但管用。
点赞 1
2026-03-08 19:02