JavaScript系列—宏任务和微任务

看这篇博文之前,先看一下下面的文章吧

《JavaScript 运行机制详解:再谈Event Loop》

http://www.ruanyifeng.com/blog/2014/10/event-loop.html

本文有参考,微信搜索《重学前端 --- Promise里的代码为什么比setTimeout先执行?》

关于宏任务和微任务

先看几道题吧

   var r = new Promise(function(resolve, reject){
    console.log("a");
    resolve()
  });
  setTimeout(()=>console.log("d"), 0)
  r.then(() => console.log("c"));
  console.log("b")

打印a b c d

再回头来看看开头的一段代码,会不会豁然开朗了呢。JS 引擎首先会把Promise对象 和 console.log("b") 两个微观任务存入执行栈,把 setTimeout(宏观任务)存入 “任务队列”

所以在输出 a 和 b 以后并不会按照预期那样立即从 “任务队列” 中读取 setTimeout,因为 then方法是微观任务Promise对象的回调函数,先于 setTimeout 执行

  Promise.resolve().then(()=>{
    console.log('1')
    setTimeout(()=>{
      console.log('2')
    },0)
  })

  setTimeout(()=>{
    console.log('3')
    Promise.resolve().then(()=>{
      console.log('4')
    })
  },0)

打印1 3 4 2

在交流群中看到有的小伙伴还是不太清楚正确的执行顺序,基于前面的介绍,大致的分析过程及草图如下:

 

1(红色):JS 引擎会把微观任务Promise存入执行栈,把宏观任务setTimeout存入 “任务队列”

2(绿色):主线程率先运行执行栈中的代码,依次输入1,然后把绿框的setTimeout存入 “任务队列”

3(蓝色):执行栈清空以后,会率先读取 “任务队列” 中最早存入的setTimeout(红框的那个),并把这个定时器存入栈中,开始执行。这个定时器中的代码都是微观任务,所以可以一次性执行,依次输出3 和 4

4(紫色):重复第3步的操作,读取 “任务队列” 中最后存入的setTimeout(绿框的那个),输出2

JavaScript系列—宏任务和微任务_第1张图片

所以最终的输出结果就是 1 3 4 2

 

 

  Promise.resolve().then(()=>{
    console.log('1')
    setTimeout(()=>{
      console.log('2')
    },0)
  })

  setTimeout(()=>{
    console.log('3')
    Promise.resolve().then(()=>{
      console.log('4')
    })
  }, 3000)

打印1 2 3 4

  setTimeout(function(){console.log(4)},0); 
  
  new Promise(function(resolve){ 
    console.log(1) 
    for( var i=0 ; i<10000 ; i++ ){
       i==9999 && resolve() 
    } 
    console.log(2) 
  }).then(function(){ 
    console.log(5) 
  }); 
  console.log(3);

另外一个会让人感到迷惑的地方就是 resolve回调函数内部的那几行代码,输出1以后接着跑1000次循环才调用resolve方法,其实resolve()的意思是把 Promise对象实例的状态从pending变成 fulfilled(即成功)

成功的回调就是对应的then方法。所以resolve() 后面的 console.log(2) 会先执行,因为 resolve() 回调函数是在本轮事件循环的末尾执行 (关于这部分内容,可以参考  Promise对象 一文)

打印1 2 3 5 4

  setTimeout(function(){console.log(4)},0); 
  
  new Promise(function(resolve){ 
    console.log(1) 
    for( var i=0 ; i<10000 ; i++ ){
      //  i==9999 && resolve() 
    } 
    console.log(2) 
  }).then(function(){ 
    console.log(5) 
  }); 
  console.log(3);

打印1 2 3 4

你可能感兴趣的:(JavaScript系列)