JavaScript事件循环严格按节奏分步推进:先执行同步代码,再清空所有微任务,然后执行一个宏任务,如此循环;微任务(如Promise.then)优先级高于宏任务(如setTimeout),即使setTimeout(…,0)写在前面也后执行。
JavaScript 事件循环不是“等所有异步做完再执行”,而是严格按节奏分步推进:先跑完当前同步代码,再清空所有微任务,接着执行一个宏任务,如此往复。
宏任务是“大块工作”,比如整个 script 脚本、setTimeout/setInterval 回调、I/O 完成通知、UI 渲染、DOM 事件处理。它们排在宏任务队列里,每次只取一个执行。
微任务是“紧急插队的小活”,比如 Promise.then/catch/finally、queueMicrotask()、MutationObserver 回调。只要同步代码一结束,引擎立刻回头把当前所有微任务全部执行完,一个不留。
关键区别在于优先级:微任务永远比宏任务快一步。哪怕 setTimeout(…, 0) 写在 Promise.then 前面,输出顺序也一定是 Promise 先、setTimeout 后。
立即学习“Java免费学习笔记(深入)”;
async 函数本身是宏任务入口,但 await 后面的表达式一旦返回 Promise,就会把后续代码包装成微任务。
例如:
async function fn() {
console.log('1');
await Promise.resolve();
console.log('2');
}
fn();
console.log('3');
输出顺序是 1 → 3 → 2。因为 await 把 console.log('2') 推进了微任务队列,而 console.log('3') 是同步代码,紧接在 fn() 调用后执行。