寫出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