瞭解js運行機制——微任務與宏任務

由一道面試題引起的思考。面試

setTimeout(function() {
  console.log(4);
}, 0);

new Promise(function(reslove) {
  console.log(1);
  reslove();
}).then(function(data) {
  console.log(3);
});

console.log(2);
複製代碼

會輸出:1,2,3,4。咱們來想一下爲何。ajax

瀏覽器中的事件循環 eventLoop,分爲同步執行棧和異步隊列,首先會執行同步的任務,當同步任務執行完以後會從異步隊列中取異步任務拿到同步執行棧中進行執行。promise

在取異步隊列時,還會有一個區分,就是區分微任務和宏任務。瀏覽器

  • microtask:微任務,優先級高,而且能夠插隊,不是先定義先執行。包括:promise 中的 then,observer,MutationObserver,setImmediate
  • macrotask:宏任務,優先級低,先定義的先執行。包括:ajax,setTimeout,setInterval,事件綁定,postMessage,MessageChannel(用於消息通信)

由於微任務的優先級較高,因此會先將微任務的異步任務取出來進行執行,當微任務的任務都執行完畢以後,會將宏任務中的任務取出來執行。異步

咱們此次來看一下上面的題,promise 中是同步任務,promise 的 .then 中是異步任務,而且是微任務。使用 setTimeout 是宏任務,即便是延時爲 0,也是宏任務。oop

因此上面的執行順序就是先將 setTimeout 加入到異步隊列的宏任務池中,而後執行 promise 中的console.log(1),再將 promise 的.then 加到異步隊列中微任務池中,再執行同步任務console.log(2),當同步任務都執行完以後,去微任務中的任務,執行console.log(3),微任務執行完以後取宏任務,執行console.log(4)。因此順序就是:1,2,3,4。post

擴展:ui

將這道面試題進行一些改造:spa

setTimeout(function() {
  console.log(4);
}, 0);

new Promise(function(reslove) {
  console.log(1);
  setTimeout(function() {
    reslove('done');
  }, 0);
  reslove('first');
}).then(function(data) {
  console.log(data);
});

console.log(2);
複製代碼

這個時候就會輸出:1,2,first,4,沒有輸出 done,有些人可能會想,應該輸出 1,2,first,4,done,這個時候你就要知道,當使用 reslove 以後,promise 的狀態就從 pedding 變成了 resolve,promise 的狀態更改以後就不能再更改了,因此 reslove('done') 就不會執行了。code

當咱們把 reslove('done') 改爲 console.log('done') 的時候,他就會輸出 1,2,first,4,done 了。

再作一個更復雜的變動:

setTimeout(function() {
  console.log(1);
}, 0);

new Promise(function(reslove) {
  console.log(2);
  reslove('p1');
  new Promise(function(reslove) {
    console.log(3);
    setTimeout(function() {
      reslove('setTimeout2');
      console.log(4);
    }, 0);
    reslove('p2');
  }).then(function(data) {
    console.log(data);
  });
  setTimeout(function() {
    reslove('setTimeout1');
    console.log(5);
  }, 0);
}).then(function(data) {
  console.log(data);
});

console.log(6);
複製代碼

輸出的結果是:2,3,6,p2,p1,1,4,5。

先執行同步的任務,new Promise 中的都是同步任務,因此先輸出 2,3,6,而後再執行微任務的,微任務能夠插隊,因此並非先定義的 p1 先執行,並且先將 p2 執行,而後執行 p1,當微任務都執行完成以後,執行宏任務,宏任務依次輸出 1,4,5,promise 的狀態不能夠變動,因此 setTimeout1 和 setTimeout2 不會輸出。

閱讀完後兩部曲

  1. 喜歡的小夥伴點個贊吧,感受對身邊人有幫助的,麻煩動動手指,分享一下。很是感謝各位花時間閱讀完,同時很感謝各位的點贊和分享。
  2. 但願各位關注一下個人公衆號吧,新的文章第一時間發到公衆號,公衆號主要發一些我的隨筆、讀書筆記、還有一些技術熱點和實時熱點,而且還有很是吸引人的我我的自費抽獎活動哦~

相關文章
相關標籤/搜索