目 录CONTENT

文章目录

JS里面的微任务与宏任务

Administrator
2023-03-11 / 0 评论 / 0 点赞 / 32 阅读 / 3132 字

JS里面的微任务与宏任务

宏任务与微任务分类

宏任务和微任务是JS中异步任务的两种分类,它们与事件循环(Event Loop)有关,影响着JS的执行顺序。

宏任务(macro task)是指那些在主线程上执行的任务,它们形成一个执行栈。宏任务包括:script (整体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering等。

微任务(micro task)是指那些在当前任务执行结束后立即执行的任务,它们不需要等待渲染。微任务包括:Promise.then, Object.observe, MutationObserver, process.nextTick等。

运行机制

事件循环的运行机制是这样的:

  • 执行一个宏任务(栈中没有就从事件队列中获取)
  • 执行过程中如果遇到微任务,就将它添加到微任务的任务队列中
  • 宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(依次执行)
  • 当前宏任务执行完毕,开始检查渲染,然后GUI线程接管渲染
  • 渲染完毕后,JS线程继续接管,开始下一个宏任务(从事件队列中获取)

通过以下的代码来测试宏任务和微任务的执行顺序:

console.log("start"); // 宏任务1,同步代码

setTimeout(() => {
  console.log("setTimeout"); // 宏任务2,异步代码
}, 0);

new Promise((resolve, reject) => {
  for (var i = 0; i < 5; i++) {
    console.log(i); // 宏任务1,同步代码
  }
  resolve(); // 修改promise状态为成功
}).then(() => {
  console.log("promise回调函数"); // 微任务1,异步代码
});

console.log("end"); // 宏任务1,同步代码

执行结果

start
0
1
2
3
4
end
promise回调函数
setTimeout

代码分析

  • 首先执行宏任务1,即主线程上的同步代码,输出start, 0, 1, 2, 3, 4, end
  • 然后遇到setTimeout,将其加入到宏任务队列等待执行
  • 然后遇到promise,立即执行,修改promise状态为成功,将其回调函数加入到微任务队列
  • 宏任务1执行完毕,查看是否有微任务队列,有则执行微任务队列中的所有任务,输出promise回调函数
  • 微任务执行完毕,执行下一个宏任务队列中的任务,输出setTimeout

试着分析一下下在代码的结果是什么?

console.log("start"); // 宏任务1,同步代码

setTimeout(() => {
  console.log("setTimeout1"); // 宏任务2,异步代码
  Promise.resolve().then(() => {
    console.log("promise1"); // 微任务3,异步代码
  });
}, 0);

new Promise((resolve, reject) => {
  console.log("promise2"); // 宏任务1,同步代码
  setTimeout(() => {
    console.log("setTimeout2"); // 宏任务3,异步代码
    resolve(); // 修改promise状态为成功
  }, 0);
}).then(() => {
  console.log("promise3"); // 微任务2,异步代码
});

console.log("end"); // 宏任务1,同步代码

上面代码运行的结果是什么呢?

经过分析以后,我们得到结果是:start, promise2, end, setTimeout1, promise1, setTimeout2, promise3

可以按照以下步骤来分析这个例子:

  • 首先执行宏任务1,即主线程上的同步代码,输出start, promise2, end
  • 然后遇到setTimeout,将其加入到宏任务队列等待执行
  • 然后遇到promise,立即执行,但是其状态由内部的setTimeout决定,所以将其加入到宏任务队列等待执行
  • 宏任务1执行完毕,查看是否有微任务队列,没有则执行下一个宏任务队列中的任务
  • 执行宏任务2,即setTimeout1,输出setTimeout1,然后将其回调函数加入到微任务队列
  • 宏任务2执行完毕,查看是否有微任务队列,有则执行微任务队列中的所有任务,输出promise1
  • 微任务执行完毕,执行下一个宏任务队列中的任务
  • 执行宏任务3,即setTimeout2,输出setTimeout2,然后修改promise状态为成功,将其回调函数加入到微任务队列
  • 宏任务3执行完毕,查看是否有微任务队列,有则执行微任务队列中的所有任务,输出promise3
0

评论区