js中的异步任务:宏任务、微任务

js的异步任务分2类:宏任务(macrotask )和微任务(microtask )

什么是宏任务、微任务

网上用食堂排队打饭或者银行排队办业务举例,个人认为不太恰当,他们并不是包含或嵌套关系。

js是单线程脚本语言,在需要执行异步任务时,就需要浏览器协助完成,形成一套事件循环机制(event loop)
浏览器在完成js交给的异步任务后,会在js的回调队列中插入一个任务,等待js的同步任务执行完成后调用执行,比如计时器、网络请求等等,
虽说异步任务都放在等待队列中,但还是有区别的,分宏任务和微任务(猜测按优先级划分?),js在调用时,优先取出微任务,并且在执行过程中如果创建了新的作业,则放在本次执行完后紧接着调用,微任务执行完成后,再取出宏任务执行。

我也来举个栗子:
你们几个人去饭店吃饭,点餐后你们要先开一局王者荣耀,打到一半有个人要上厕所,但一致要他打完这局才能去;打完后菜已上齐但他要先去厕所,剩下的人就要等他回来后才能开饭。
(上厕所就是微任务,很急,吃饭就是宏任务,等紧急事情办法才能开始,整个过程就是一次事件循环)

宏任务、微任务有哪些

宏任务包括:script(整体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering。
微任务包括: Promises, Object.observe, MutationObserver

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

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

实例1

setTimeout(function(){
    console.log('1');
});
new Promise(function(resolve){          
    console.log('2');
    resolve();
}).then(function(){         
    console.log('3');
});         
console.log('4'); 
  1. 遇到setTimout,异步宏任务,放入宏任务队列中;
  2. 遇到new Promise,Promise在实例化的过程中所执行的代码都是同步进行的,所以输出2;
  3. 而Promise.then中注册的回调才是异步执行的,将其放入微任务队列中
  4. 遇到同步任务console.log(‘4’);输出4;主线程中同步任务执行完
  5. 从微任务队列中取出任务到主线程中,输出3,微任务队列为空
  6. 从宏任务队列中取出任务到主线程中,输出1,宏任务队列为空,结束~

输出:2 4 3 1

实例2

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,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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章