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

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