简单易懂的宏任务和微任务执行顺序

273次阅读  |  发布于3年以前

背景

很多朋友在写面试题:宏任务与微任务的执行时机时,容易犯迷糊。之前我也写过两篇文章,这次加上详细的讲解,让大家更容易理解

什么是宏任务、微任务?

1.首先要称得上是宏任务、微任务的,必须是一个回调函数,例如:

setTimeout(getList,5000);

这个getList就是一个回调函数

2.必须是异步执行的回调函数

3.区分宏任务与微任务

宏任务:

渲染事件(如解析 DOM、计算布局、绘制);

用户交互事件(如鼠标点击、滚动页面、放大缩小等);

JavaScript 脚本执行事件;

网络请求完成、文件读写完成事件

微任务:

MutationObserver;

Promise.resolve();

就这么些任务,在浏览器环境中,系统已经把他们区分成了宏任务和微任务,并没有其他特殊的含义!!死记下来就行了


每个宏任务对应了一个微任务队列

每一个宏任务,都对应了一个微任务队列,没什么特别的,你现在知道了这点,而且知道了哪些是宏任务和微任务

全局同步代码,是特殊的宏任务

全局的同步执行代码,也要看成一个宏任务,那这个宏任务,也对应了他的微任务队列,例如:

for (let i=0;i<1000;i++){

//dosomething

}
Promise.resolve().then(()=>{
  //dosomething
})

setTimeout(()=>{
  //dosomething
})

当for循环(全局的同步代码执行完毕后,就会开始执行微任务队列的任务),这个时候就会去执行Promise.resolve().then里面的代码。

当全局同步代码这个宏任务对应的微任务队列执行完毕以后,就会去继续执行宏任务。

那么接下来,就会执行setTImeout回调里面的代码

假设宏任务里面再继续有微任务

for (let i=0;i<1000;i++){

//dosomething

}
Promise.resolve().then(()=>{
  console.log(1);
})

setTimeout(()=>{
  console.log(2);
  setTimeout(()=>{
   console.log(3);
  })
  Promise.resolve().then(()=>{
  console.log(4);
})
})

打印顺序是:1 2 4 3

分析:

当全局的同步代码(宏任务)执行完毕后,执行全局宏任务对应的微任务队列,输出1.

清空全局同步代码对应的微任务队列后,开始执行下一个宏任务,下一个宏任务是定时器回调函数,输出2.

这个定时器宏任务对应了一个微任务队列,此时执行Promise.resolve.then这个微任务,输出4

最后执行完这个微任务队列后,继续执行下一个宏任务,输出3


加餐

大家看完上面,可能只知道了宏任务和微任务的执行时机,但是整个系统是怎么任务调度的?

其实大家可以把整个页面任务调度系统看成是一个for循环

整个系统的任务调度

周而复始,像一个for循环一样。

用一张图来讲解就是:

以上就是微任务和宏任务的执行机制

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8