淺談瀏覽器執行環境下的event loop機制

xuerensusu發表於2018-05-26

先來看一張圖片

淺談瀏覽器執行環境下的event loop機制

主執行緒呼叫棧

所謂的JS單執行緒是指一個瀏覽器的主程式中只有一個JS執行執行緒。JS的執行執行緒的呼叫棧(stack)都是同步的(因為是單執行緒,所以一次只能做一件事),JS執行執行緒的主執行緒上的所有同步的任務都會放在這個執行棧中。

console.log('event loop1');
console.log('event loop2');
複製程式碼

簡單如以上程式碼,就被放在Call Stack執行棧中順序執行,然後遵循先進後出,後進先出的原則銷燬。輸出的順序是:先是event loop1後是 event loop2。

事件迴圈機制

如果執行過程中遇到DOM操作、ajax或setTimeout等非同步操作的時候,會提交給相應的非同步程式處理。

如:DOM操作是瀏覽器核心的DOM binding模組處理;Ajax是瀏覽器核心的Network模組處理;setTimeout是由瀏覽器核心的Timer模組處理。

處理完的回撥就被推入到任務佇列callback queue(應該叫event queue可能更準確些)。等待主執行緒的呼叫棧空閒。

一旦主執行緒的task執行完畢後,瀏覽器執行環境的Event Loop機制就查詢任務佇列,把佇列裡排在前面的回撥壓入主呼叫棧執行,如此重複。這個過程就稱為事件迴圈

所以我們就可以很容易理解以下程式碼:

console.log('hello');
setTimeout(function(){
    console.log('setTimeout1');
})
setTimeout(function(){
    console.log('setTimeout2');
})
console.log('world');
複製程式碼

結果依次是:hello world setTimeout1 setTimeout2


任務佇列

淺談瀏覽器執行環境下的event loop機制

任務佇列存在兩種型別,一種是microtask queue,還有一種是macrotask queue。

macro-task(巨集任務)包括:script(整體程式碼),setTimeout,setInterval, setImmediate(node.js),I/O,UI rendering。

micro-task(微任務)包括:process.nextTick(node.js),Promises,Object.observe, MutationObserver。

事件迴圈主執行緒進入呼叫棧開始,看到setTimeout處理完就會新增macrotask 佇列中。看到Promises處理完就會新增到microtask佇列中。等到主執行緒呼叫棧都執行完任務後,會優先按執行microtask queue,全部執行完。然後才會取macrotask queue排在隊首的執行。

看下面這段程式碼:

console.log(1);
setTimeout(() => {
    console.log(2);
}, 0);
new Promise((resolve, reject) => {
    console.log(3);
    Promise.resolve().then(() => {
        console.log(4);
    })
    resolve();
}).then(() => {
    console.log(6);
})
console.log(7);
複製程式碼

執行順序依次是:1 3 7 4 6 2 。這說明mic-rotask中的回撥將優先執行。

ps:這個網站可以實現程式碼的視覺化 latentflip.com/loupe/,有興趣的可以看看。

參考文章:

zhuanlan.zhihu.com/p/26238030 blog.csdn.net/lin_credibl…

相關文章