js非同步之宏任務(marcroTask)和微任務(microTask)

2020-10-08 12:00:49

先看一到面試題

寫出console.log的輸出順序

console.log(100);

setTimeout(()=>{
    console.log(200);
})


setTimeout(()=>{
    console.log(201);
})


Promise.resolve().then(()=>{
    console.log(300);
})

console.log(400);


// 100 400 300 200 201


// 為什麼300比200先列印

為什麼300比200先列印這裡就引出了宏任務和微任務????

什麼是宏任務和微任務

在這裡插入圖片描述

宏任務包括:setTimeout setInterval Ajax DOM事件
微任務:Promise async/await
微任務比宏任務的執行時間要早

同步非同步問題

首先,你要知道javascript是單執行緒語言。js任務需要排隊順序執行,如果一個任務耗時過長,後邊一個任務也的等著,但是,假如我們需要瀏覽新聞,但新聞包含的超清圖片載入很慢,總不能網頁一直卡著直到圖片完全出來,所以將任務設計成了兩類:

同步任務
非同步任務

當我們開啟網站時,網頁的渲染過程就是一大堆同步任務,像頁面骨架和頁面元素的渲染,而載入圖片、音樂之類的任務就是非同步任務,看一下下邊導圖:

在這裡插入圖片描述
同步和非同步任務分別進入不同的執行「場所」,同步進入主執行緒,非同步進入Event Table並註冊函數。當指定的事情完成時,Event Table會將這個函數移入Event Queue。主執行緒內的任務執行完畢為空,回去了Event Queue讀取對應的函數,進入主執行緒。

上述過程會不斷重複,也就是常說的Event Loop(事件迴圈)。

但是,JS非同步還有一個機制,就是遇到宏任務,先執行宏任務,將宏任務放入event queue,然後再執行微任務,將微任務放入micro task queue,但是,這兩個queue不是一個queue。當你往外拿的時候先從微任務裡拿這個回撥函數,然後再從宏任務的queue拿宏任務的回撥函數,如下圖:

在這裡插入圖片描述
在這裡插入圖片描述
所以最終的執行步驟為:

先是將所有同步程式碼執行完畢後,call back(任務棧)清空
然後執行當前的微任務
然後執行當前的宏任務
再嘗試DOM的渲染
最後觸發Event Loop

三、執行順序

1.主執行緒上宏任務、微任務執行順序

console.log('---start---');//第一輪主執行緒
 
setTimeout(() => {
  console.log('setTimeout');  // 將回撥程式碼放入個宏任務佇列,第二輪宏任務執行
}, 0);
 
new Promise((resolve, reject) => {
  console.log('---Promise第一輪微任務同步執行---');//第一輪微任務同步執行
  resolve()
}).then(()=>{
  console.log('Promise.then範例成功回撥執行'); // 將回撥程式碼放入微任務佇列,第一輪宏任務執行完後立即執行
});
 
console.log('---end---');//第一輪主執行緒結束

在這裡插入圖片描述

執行順序:主執行緒 >> 主執行緒上建立的微任務 >> 主執行緒上建立的宏任務

2.宏任務中包含微任務

// 宏任務佇列 1
setTimeout(() => {
  // 宏任務佇列 2.1
  console.log('timer_1');
  setTimeout(() => {
    // 宏任務佇列 3
    console.log('timer_3')
  }, 0)
  new Promise(resolve => {
    resolve()
    console.log('new promise')
  }).then(() => {
    // 微任務佇列 1
    console.log('promise then')
  })
}, 0)
 
setTimeout(() => {
  // 宏任務佇列 2.2
  console.log('timer_2')
}, 0)
console.log('========== Sync queue ==========')

執行順序:主執行緒 >> 主執行緒上的宏任務佇列1 >> 宏任務佇列1中建立的微任務

========== Sync queue ==========
 
1 timer_1
2 new promise
3 promise then
4 timer_2
5 timer_3