return Promise.resolve()对JavaScript事件循环的影响及执行顺序疑问
为什么
Promise.resolve().then()会让输出变成3 2 1? 嘿,这个问题其实戳中了JavaScript事件循环里**宏任务(macrotasks)和微任务(microtasks)**的优先级差异,很多刚深入事件循环的开发者都会在这里踩坑,我来给你掰扯清楚:
首先,先把你的代码拆解成执行步骤,一步步看:
setTimeout(()=> console.log('1')); // 这是一个宏任务 Promise.resolve('whatever').then(()=>console.log('2')); // 这是一个微任务 console.log('3'); // 同步代码
执行顺序的核心逻辑:
JavaScript的事件循环遵循「先同步,再微任务,最后宏任务」的优先级:
先执行所有同步代码:
代码从上到下走,console.log('3')是同步任务,会立即执行,所以先输出3。同步代码执行完后,清空当前微任务队列:
同步执行栈空了之后,事件循环会先检查微任务队列里有没有等待执行的任务。Promise.resolve().then()的回调就属于微任务,它会被加入微任务队列,这时候会立即执行这个回调,输出2。微任务队列清空后,才会执行宏任务队列里的任务:
等所有微任务都处理完,事件循环才会去看宏任务队列。setTimeout的回调是宏任务,这时候才会被执行,输出1。
为什么你之前预期错了?
你可能误以为Promise.resolve().then()和setTimeout是同级的任务,但实际上它们分属不同的任务队列:
- 宏任务队列:存放
setTimeout、setInterval、I/O操作、UI渲染这类任务,每次事件循环只取一个宏任务执行。 - 微任务队列:存放
Promise的then/catch/finally、MutationObserver、Node.js里的process.nextTick这类任务,每次执行完同步代码或一个宏任务后,会把整个微任务队列清空才会继续。
简单说就是:微任务的优先级比宏任务高,会插队在宏任务前面执行。
如果把你的代码稍微改一下,多加几个微任务和宏任务,你就能更清楚看到这个规律:
setTimeout(() => console.log('宏任务1')); Promise.resolve().then(() => { console.log('微任务1'); Promise.resolve().then(() => console.log('微任务2')); }); setTimeout(() => console.log('宏任务2')); console.log('同步代码');
输出会是:同步代码 → 微任务1 → 微任务2 → 宏任务1 → 宏任务2,完美验证了微任务队列会被一次性清空的规则。
内容的提问来源于stack exchange,提问作者moatazelmohtaseb
相关产品推荐
相关产品推荐

