宏任务、微任务,js事件循环

236 阅读2分钟

什么是宏任务、微任务

先来了通俗易懂的例子: 去银行办理业务的人就是一个个宏任务,当宏任务P1在柜台办理业务时,其它任务都需等待,当一个宏任务P1办理业务结束时,柜台职员会询问他还有没有其它微任务,如果他还有其他业务,则其他宏任务都需等待。就是微任务是在宏任务之前执行。

宏任务、微任务有哪些

宏任务包括:script(整体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering。

微任务包括: Promise.then catch finally, Object.observe, MutationObserver

宏任务、微任务的执行顺序

js是单线程的,在一个时间只能做一件事,需要事件循环来调度

执行顺序:先执行同步代码,遇到异步宏任务则将异步宏任务放入宏任务队列中,遇到异步微任务则将异步微任务放入微任务队列中,当所有同步代码执行完毕后,再将异步微任务从队列中调入主线程执行,微任务执行完毕后再将异步宏任务从队列中调入主线程执行,一直循环直至所有任务执行完毕。

实例剖析

setTimeout(()=>{
  new Promise(resolve =>{
  	resolve();
  }).then(()=>{
  	console.log('test');
  });

  console.log(4);
});

new Promise(resolve => {
  resolve();
  console.log(1)
}).then( () => {
  console.log(3);
  Promise.resolve().then(() => {
    console.log('before timeout');
  }).then(() => {
    Promise.resolve().then(() => {
      console.log('also before timeout')
    })
  })
})
console.log(2);
  1. 遇到setTimeout,异步宏任务,将() => {console.log(4)}放入宏任务队列中;
  2. 遇到new Promise,new Promise在实例化的过程中所执行的代码都是同步进行的,所以输出1;
  3. 而Promise.then中注册的回调才是异步执行的,将其放入微任务队列中
  4. 遇到同步任务console.log(2),输出2;主线程中同步任务执行完
  5. 从微任务队列中取出任务到主线程中,输出3,此微任务中又有微任务,Promise.resolve().then(微任务a).then(微任务b),将其依次放入微任务队列中;
  6. 从微任务队列中取出任务a到主线程中,输出 before timeout;
  7. 从微任务队列中取出任务b到主线程中,任务b又注册了一个微任务c,放入微任务队列中;
  8. 从微任务队列中取出任务c到主线程中,输出 also before timeout;微任务队列为空
  9. 从宏任务队列中取出任务到主线程,此任务中注册了一个微任务d,将其放入微任务队列中,接下来遇到输出4,宏任务队列为空
  10. 从微任务队列中取出任务d到主线程 ,输出test,微任务队列为空,结束~ 控制台测试输出:1 2 3 before timeout also before timeout 4 test