likes
comments
collection
share

都2023年了,还有人没搞懂微任务与宏任务吗?

作者站长头像
站长
· 阅读数 14
都2023年了,还有人没搞懂微任务与宏任务吗?

大家都知道JavaScript是一门单线程执行的编程语言。代码执行顺序就是解析一行执行一行。小伙心里就在想那假如上一行执行非常久,那下一行该咋办? 那就等待呗!还能咋整...

    for (var i = 0; i < 1000000000; i++) {
       console.log("我没完,你就等着吧~")
    }
    console.log("我等上面的任务结束呀"); 

通过以上代码可以很明显的看到,如果循环没执行完。下面写的代码也不执行,就要等着它! 那如果我们来写一个定时器呢?它需要等吗?

    setTimeout(()=>{
      console.log("你可别等我,会疯掉的~")
    },10000)
    console.log("我不等你啦,我先执行了"); 

通过2个极其简单的小粒子,我们就知道了。setTimeout是一个异步呗!还有哪些API是异步这里就不做多余的赘述了。 兄弟们只要明白异步任务不会去阻塞同步代码的执行~

上面已经把异步的概念给引了出来,接下来咱就可以研究研究微任务与宏任务了, 首先微任务与宏任务都是异步任务 他们2个之间不存在谁等谁这种事情了!只存在谁先推到异步队列,谁先执行的现象~

都2023年了,还有人没搞懂微任务与宏任务吗?

我相信大家在网上或者博客上,都看过这种图。或者类似的这种图。对吧~ 但是看完还是一脸懵逼的,估计占了70%

那下面我就来说一下,我对这2个任务执行顺序的理解。 仅供参考:

首先根据公式:同步任务>微任务>宏任务 优秀级从左到右

   console.log('我是同步任务1')
   setTimeout(()=>{
      console.log("我是你们的洪流猛兽,宏任务~")
   })
   console.log('我是同步任务2')
   
   Promise.resolve().then(res=>{ console.log("我是你们的危险份子,微任务~") })

通过这简单的代码,套用上面的公式,咱已经就有答案了。打印出来肯定是

  1. 我是同步任务1
  2. 我是同步任务2
  3. 我是你们的危险份子,微任务~
  4. 我是你们的洪流猛兽,宏任务~

浏览器效果如下:

都2023年了,还有人没搞懂微任务与宏任务吗?

加大难度,如果宏任务里面套一个微任务呢,再看一下执行顺序

   console.log('我是同步任务1')
   setTimeout(()=>{
      console.log("我是你们的洪流猛兽,宏任务~")
      Promise.resolve().then(res=>{ console.log("我要跟着洪流猛兽,同流合污,微任务~") })
   })
   console.log('我是同步任务2')
   
   Promise.resolve().then(res=>{ console.log("我是你们的危险份子,微任务~") })

好像也能套上面的公式:同步任务->微任务->宏任务

首先2个同步任务先跑~

  1. 我是同步任务1
  2. 我是同步任务2

然后再看微任务,有一个“危险份子” 执行吧~

  1. 我是你们的危险份子,微任务~

然后再执行宏任务,此时注意:这个宏任务里面“洪流猛兽”是一个同步的,然后Promise是异步的 所以:

  1. 我是你们的洪流猛兽,宏任务~
  2. 我要跟着洪流猛兽,同流合污,微任务~

浏览器效果如下:

都2023年了,还有人没搞懂微任务与宏任务吗?

咱再继续加难度,此时又大有不同哦..

   console.log('我是同步任务1')
   setTimeout(()=>{
      console.log("我是你们的洪流猛兽,宏任务~")
      Promise.resolve().then(res=>{ console.log("我要跟着洪流猛兽,同流合污,微任务~") })
   })
   console.log('我是同步任务2')
   
   Promise.resolve().then(res=>{ 
        console.log("我是你们的危险份子,微任务~") 
        setTimeout(()=>{
         console.log("我与危险份子相互拥抱,宏任务~")
        })
   })

此时套用上面的公式好像就有点牵强了,按照上面公式走的话:同步任务>微任务>宏任务,如下:

  1. 我是同步任务1
  2. 我是同步任务2
  3. 我是你们的危险份子,微任务~
  4. 我与危险份子相互拥抱,宏任务~
  5. 我是你们的洪流猛兽,宏任务~
  6. 我要跟着洪流猛兽,同流合污,微任务~

此时大家想一下,这个结果对吗? 看打印结果吧

都2023年了,还有人没搞懂微任务与宏任务吗?

此刻明显就有了出入,这里就要引出一个概念了。就是宏任务队列与微任务队列

JS在执行代码时,遇到异步任务都会往队列里面推。 想象一个场景公司食堂排队:食堂管理员看见财务负责人,CEO,项目经理,销售部员工1,程序员1,销售部员工2 ,程序员3,程序员2。

管理员为了拍马屁肯定是按照:CEO->财务负责人->项目经理 直接安排他们VIP包房服务来一套 此刻他们的角色在代码中就是同步任务,先执行!

此刻管理员又看到,销售部员工1,程序员1,销售部员工2 ,程序员3,程序员2。那么他又要纠正一下队列了。

首先销售部的进微任务队列:销售部员工1,销售部员工2 优先在宏任务之前

然后技术部的进宏任务队列:程序员1,程序员2,程序员3 在后

这里再次引出公式:同步任务->微任务->宏任务。但是如果:销售部员工1与程序员1,两人是好基友。结伴同行排队呢

   console.log('CEO')
   setTimeout(()=>{
      console.log("程序员2")
   })
   console.log('财务负责人')
   
   Promise.resolve().then(()=>{ 
        console.log("销售部员工1") 
        setTimeout(()=>{
         console.log("程序员1")
        })
   })

此时管理员看到这情况,一样会把它们区分开。你是哪个队的,就站哪个队。。 骨子里面定死的,不是你跟谁后面,就有饭吃。

CEO,财务负责人 同步的任务,走~ 进包厢服务~

然后销售部的进微任务队列:销售部员工1,但是你后面跟着:程序员1,他不是你们销售部的,没资格站这里。去宏任务队列排着

然后技术部的进宏任务队列:程序员2,程序员1

所以顺序就是:

  1. CEO
  2. 财务负责人
  3. 销售部员工1
  4. 程序员2
  5. 程序员1

刚才还有一种情况,如果是宏任务后面跟着微任务呢? 比如程序员2带着销售部员工2呢?

   console.log('CEO')
   setTimeout(()=>{
      console.log("程序员2")
       Promise.resolve().then(res=>{ console.log("销售部员工2") })
   })
   console.log('财务负责人')
   
   Promise.resolve().then(()=>{ 
        console.log("销售部员工1") 
        setTimeout(()=>{
         console.log("程序员1")
        })
   })

此时管理员看到这情况,一样会把它们区分开。你是哪个队的,就站哪个队。。

CEO,财务负责人 同步的任务,走~ 进包厢服务~

然后销售部的进微任务队列:销售部员工1,但是你后面跟着:程序员1,他不是你们销售部的,没资格站这里。去宏任务队列排着

此刻程序员1因为是被微任务队列赶出来的,所以要进宏任务,此刻进宏任务一看,为什么前面有个销售部呀?此刻他就呼叫管理员,你不管管么?他不是宏任务这个队的。管理员说:他的身份本来是可以优先的,但是他愿意站你们那个队,就让他站着,你就默默站后面吧!

然后技术部的进宏任务队列:程序员2,销售部员工2,程序员1

所以顺序就是:

  1. CEO
  2. 财务负责人
  3. 销售部员工1
  4. 程序员2
  5. 销售部员工2
  6. 程序员1

上面的场景大家一定要花一点想象力理解一下。接下来就是终极面试题了

    console.log('CEO');
    
    setTimeout(function () {
      console.log('程序员1');
      
      Promise.resolve().then(res => { console.log('销售4') })
 
      new Promise(function (resolve) { 
        console.log('程序员2'); 
        resolve(); 
      }).then(function () { 
        console.log('销售5') 
      })
      
    })

    Promise.resolve().then(res=>{ console.log('销售1') })
    
    new Promise(function (resolve) { 
      console.log('财务主管'); 
      resolve(); 
    }).then(function () { 
      console.log('销售2') 
    })

    setTimeout(function () {
      console.log('程序员3'); 
      
      Promise.resolve().then(res => { console.log('销售3') })
      
      new Promise(function (resolve) { 
        console.log('程序员6'); resolve(); 
      }).then(function () { 
        console.log('销售6') 
      })
    })

答案依次打印如下:

  1. CEO
  2. 财务主管
  3. 销售1
  4. 销售2
  5. 程序员1
  6. 程序员2
  7. 销售4
  8. 销售5
  9. 程序员3
  10. 程序员6
  11. 销售3
  12. 销售6