找回密码
 立即注册
首页 业界区 业界 Web前端入门第 68 问:JavaScript 事件循环机制中的微任 ...

Web前端入门第 68 问:JavaScript 事件循环机制中的微任务与宏任务

神泱 2025-9-25 19:39:44
JS 是单线程语言。这句话对不对?
按照目前的情况来看,JS 自从支持了 Web Worker 之后,就不再是单线程语言了,但 Worker 的工作线程与主线程有区别,在 Worker 的工作线程中无法直接操作 DOM、window 对象或大多数浏览器 API(如 localStorage),Worker 的全局对象也不再是 window 对象,而是 self。
Worker 中的事件循环与主线程相互独立,互不影响,但执行顺序还是得遵循 JS 的语法规则。
宏任务

宏任务表示执行时间较长的任务,在每次时间循环时只会执行一个宏任务,执行完毕后处理微任务队列,所有微任务都执行完毕后进入下一个宏任务。
JS 常见宏任务类型:

  • 定时器任务:setTimeout / setInterval
  • DOM 事件回调(如 click、scroll)
  • I/O 操作(如文件读取、网络请求)
  • 浏览器用于执行动画的方法 requestAnimationFrame ,执行时机与渲染相关
  • Node.js 环境的 setImmediate
  • script 标签内主线程的同步代码(整体作为一个宏任务)
微任务

微任务表示更轻量的异步任务,当宏任务执行完毕之后立即执行。
JS 常见微任务类型:

  • Promise.then() / Promise.catch() / Promise.finally()
  • 浏览器监听 DOM 变化的 API 对象,比如:MutationObserver
  • 手动添加微任务API方法:queueMicrotask()
  • nodejs 中的 process.nextTick()
代码解析

看这么一段代码:
  1. (function() {
  2.   console.log(1)
  3.   setTimeout(() => { console.log(2); });
  4.   queueMicrotask(() => console.log(3))
  5.   new Promise(resolve => {
  6.     console.log(4);
  7.     setTimeout(() => {
  8.       resolve();
  9.       console.log(5);
  10.     }, 0);
  11.     Promise.resolve().then(() => console.log(6));
  12.     console.log(7);
  13.   }).then(() => {
  14.     console.log(8);
  15.     Promise.resolve().then(() => console.log(9));
  16.   });
  17.   console.log(10);
  18. })();
复制代码
分析代码:
  1. (function() {
  2.   console.log(1) // 同步任务
  3.   setTimeout(() => { console.log(2); });
  4.   queueMicrotask(() => console.log(3))
  5.   new Promise(resolve => {
  6.     console.log(4); // 同步任务
  7.     setTimeout(() => { // 宏任务
  8.       resolve(); // 宏任务的同步任务
  9.       console.log(5); // 宏任务中的同步任务
  10.     }, 0);
  11.     Promise.resolve().then(() => console.log(6)); // 微任务
  12.     console.log(7); // 同步任务
  13.   }).then(() => { // 微任务
  14.     console.log(8); // 微任务中的同步任务
  15.     Promise.resolve().then(() => console.log(9)); // 微任务中的微任务
  16.   });
  17.   console.log(10); // 同步任务
  18. })();
复制代码
第一轮

首先同步代码的宏任务优先级最高,不管微任务还是宏任务,同步代码都会先执行。
所以上面代码会优先执行:
  1. console.log(1)
  2. console.log(4);
  3. console.log(7);
  4. console.log(10);
复制代码
接着开始处理微任务:
  1. queueMicrotask(() => console.log(3))
  2. Promise.resolve().then(() => console.log(6));
复制代码
微任务处理完,开始执行下一轮宏任务。
第二轮

这一轮中的宏任务只有一个 setTimeout,执行完之后由于没有微任务队列,所以直接执行下一轮宏任务。
  1. setTimeout(() => { console.log(2); });
复制代码
第三轮

这一轮的宏任务中有同步代码。
  1. setTimeout(() => { // 宏任务
  2.   resolve(); // 宏任务的同步任务
  3.   console.log(5); // 宏任务中的同步任务
  4. }, 0);
复制代码
在执行完 resolve() 之后,会将 Promise.then 的回调函数放入微任务队列中,所以在宏任务执行完之后会开始微任务:
  1. then(() => { // 微任务
  2.   console.log(8); // 微任务中的同步任务
  3.   Promise.resolve().then(() => console.log(9)); // 微任务中的微任务
  4. })
复制代码
最终的打印顺序
  1. 1
  2. 4
  3. 7
  4. 10
  5. 3
  6. 6
  7. 2
  8. 5
  9. 8
  10. 9
复制代码
执行流程图

JS 代码逐行执行,在遇到宏任务时,整个代码块丢到宏任务队列,在遇到微任务时,将微任务丢到本次事件循环中的微任务队列,本次事件循环执行完之后,再执行微任务队列中的任务,微任务执行完之后开始下一个宏任务执行。
JS 代码执行机制:
1.png

宏任务执行机制:
2.png

写在最后

JS 中的代码执行流程永远都是事件循环机制,这是 JS 的任务调度核心,理解事件循环机制,才能在开发中游刃有余~~

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册