JS時間迴圈巨集任務微任務 講解+面試題
阿新 • • 發佈:2021-11-13
什麼是事件迴圈?
事實上我把事件迴圈理解成我們編寫的JavaScript和瀏覽器或者Node之間的一個橋樑
瀏覽器的事件迴圈是一個我們編寫的JavaScript程式碼和瀏覽器API呼叫(setTimeout/AJAX/監聽事件等)的一個橋樑, 橋樑之間他們通過回撥函式進行溝通。
Node的事件迴圈是一個我們編寫的JavaScript程式碼和系統呼叫(file system、network等)之間的一個橋樑, 橋樑 之間他們通過回撥函式進行溝通的
JS程式碼執行流程
- 定義變數name;
- 執行log函式,函式會被放入到呼叫棧中執 行;
- 呼叫bar()函式,被壓入到呼叫棧中,但是執 行未結束;
- bar因為呼叫了sum,sum函式被壓入到調 用棧中,獲取到結果後出棧;
- bar獲取到結果後出棧,獲取到結果result;
- 將log函式壓入到呼叫棧,log被執行,並且 出棧
瀏覽器中事件迴圈
如果執行JS中存在非同步操作,例如setTimeout(),則會被放入呼叫棧中,執行會結束,不會阻塞後面程式碼執行
其實內部呼叫 web API,在合適的時機將函式加入到事件佇列中
事件佇列中的函式會被放入呼叫棧,然後被執行。
巨集任務、微任務
事件迴圈中事實上有兩個佇列
- 巨集任務佇列(macrotask queue):ajax、setTimeout、setInterval、DOM監聽、UI Rendering等
- 微任務佇列(microtask queue):Promise的then回撥、 Mutation Observer API、queueMicrotask()等
那麼事件迴圈對於兩個佇列的優先順序是怎麼樣的呢?
- main script中的程式碼優先執行(編寫的頂層script程式碼);
- 在執行任何一個巨集任務之前(不是佇列,是一個巨集任務),都會先檢視微任務佇列中是否有任務需要執行
- 也就是巨集任務執行之前,必須保證微任務佇列是空的;
- 如果不為空,那麼久優先執行微任務佇列中的任務(回撥)
面試題
1
setTimeout(function () { console.log("set1"); new Promise(function (resolve) { resolve(); }).then(function () {new Promise(function (resolve) { resolve(); }).then(function () { console.log("then4"); }); console.log("then2"); }); }); new Promise(function (resolve) { console.log("pr1"); resolve(); }).then(function () { console.log("then1"); }); setTimeout(function () { console.log("set2"); }); console.log(2); queueMicrotask(() => { console.log("queueMicrotask1") }); new Promise(function (resolve) { resolve(); }).then(function () { console.log("then3"); }); // pr1 // 2 // then1 // queuemicrotask1 // then3 // set1 // then2 // then4 // set2
2
async function async1 () { console.log('async1 start') await async2(); console.log('async1 end') } async function async2 () { console.log('async2') } console.log('script start') setTimeout(function () { console.log('setTimeout') }, 0) async1(); new Promise (function (resolve) { console.log('promise1') resolve(); }).then (function () { console.log('promise2') }) console.log('script end') // script start // async1 start // async2 // promise1 // script end // aysnc1 end // promise2 // setToueout
注意:
Promise中的為同步程式碼塊,then後為非同步 微任務
Async 函式中:await前的可以看做Promise外部的diamante
await相當於在執行Promise中的為同步程式碼塊
await後的相當於在執行then的回撥 微任務