一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

JavaScript 事件循环机制如何运作

时间:2026-07-11 11:24:03 编辑:袖梨 来源:一聚教程网

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免费学习笔记(深入)”;

事件循环每一轮具体做什么

  • 执行当前宏任务中的全部同步代码(比如 console.log、函数调用、变量赋值)
  • 遇到 setTimeout → 放入宏任务队列;遇到 Promise.then → 放入微任务队列
  • 同步代码执行完毕,调用栈清空 → 立刻检查微任务队列
  • 依次执行所有已排队的微任务(包括过程中新产生的微任务)
  • 微任务队列清空后,浏览器可能触发一次 UI 渲染(如重绘)
  • 从宏任务队列头部取出下一个任务,开始新一轮循环

async/await 实际怎么参与调度

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() 调用后执行。

常见误区提醒

  • setTimeout(..., 0) 不代表“立刻执行”,只是尽快安排进宏任务队列,至少要等当前同步代码 + 所有微任务走完
  • Promise.then 不是“马上运行”,它注册的是微任务,必须等本轮同步结束才触发
  • fetch() 返回 Promise,但 .then 或 await 才决定回调何时加入微任务队列,不是请求发出那一刻就排队
  • 多个 Promise.then 链式调用,每个 .then 都生成新微任务,会按注册顺序依次执行

热门栏目