宏任务,微任务!

123 阅读3分钟

昨天我老师发给我一段代码,我兴致勃勃当然觉得没问题了,于是我就推演了一下运行结果,结果是疯狂打脸。我拿着我的猜想和结论,去问我的老师,结果我的大脑好像停止了运行,离正确结果越来越远,我沉思了一会儿,我还是先去复盘一下相关内容吧。

宏任务和微任务是怎么执行的

promise.drawio.svg

注意以下几点:

  • Promise 优先于 setTimeout 宏任务,所以 setTimeout 回调会最后执行;
  • Promise 一旦被定义就会立即执行;
  • Promise 的 resolve 和 reject 是异步执行的回调。所以 resolve() 会被放到回调队列中,在主函数执行完和 setTimeout 之前调用;
  • await 执行完后,会让出线程。async 标记的函数会返回一个 Promise 对象;

例1

setTimeout(function(){
 console.log('1');
});
new Promise(function(resolve){		    
 console.log('2');
resolve();
}).then(function(){		    
 console.log('3');
}).then(function(){
 console.log('4')
}); 		
 console.log('5');
  1. 队列开始,迎面遇见setTimeout,放入宏任务队列中;
  2. 遇到new Promise,new Promise在实例化的过程中所执行的代码都是同步进行的,所以输出:'2'
  3. 而Promise.then中的回调是异步的,所以依次把它们放入微任务队列中;
  4. 遇到同步任务console.log('5');,输出:'5',主线程中同步任务执行完;
  5. 提取微任务队列到主线程,依次输出:'3'、'4',微任务队列清空;
  6. 提取宏任务队列到主线程,输出:'1',宏任务队列为空;
  7. 队列结束;

例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,放入宏任务队列中;
  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',微任务队列清空;

例3

async function async1() {
    console.log('async1 start');
    await async2();
    console.log('async1 end');
}
 
async function async2() {
    console.log('async2');
}
 
console.log('script start');
 
setTimeout(()=>{
    console.log('setTimeout');
},0)
 
async1();
 
new Promise((resolve)=>{
    console.log('promise1');
    resolve();
}).then(()=>{
    console.log('promise2');
});
 
console.log('script end');

//script start
//async1 start
//async2
//promise1
//script end
//async1 end
//promise2
//setTimeout
  1. 队列开始,前两个是异步,迎面输出:'script start'
  2. 遇到setTimeout,挂起console.log('setTimeout');,加入宏任务队列;
  3. 调用async1(),输出:'async1 start',遇到await(依赖async2()执行结果,输出:'async2'),将console.log('async1 end');挂起放入微任务队列;
  4. 执行Promise,输出:'promise1',回调.then()是异步,所以将console.log('promise2');挂起放入微任务队列;
  5. 执行同步任务console.log('script end');,输出:'script end',主线任务结束;
  6. 提取微任务队列到主线程,依次输出:'async1 end'、'promise2',微任务队列清空;
  7. 提取宏任务队列到主线程,输出:'setTimeout',宏任务队列清空;

参考文献:blog.csdn.net/MFWSCQ/arti…