首頁  >  文章  >  web前端  >  深入了解JS事件循環機制

深入了解JS事件循環機制

零到壹度
零到壹度原創
2018-04-09 14:47:411833瀏覽


這篇文章給大家分享的內容是深入了解JS事件循環機制,有著一定的參考價值,有需要的朋友可以參考一下

#寫在前面

js裡的事件循環機制十分有趣。從很多面試題目也可以看出來,考察簡單的setTimeout也就是考察這個機制的。
在之前,我只是簡單地認為由於函數執行很快,setTimeout執行時間即便為0也不會馬上輸出,而是等待函數執行完後再輸出。這只對了一半。
其實其運作機制就是js中的事件循環機制,在這個循環機制中呢,又與call Stack和task queue有關。

js事件循環機制

事件循環機制呢,簡單點來說,就是在執行上下文的過程中,對函數的入棧與出棧。執行前函數先入棧,執行完後函數出棧。如若遇到了一些非同步操作像回呼函數以及ajax、setTimeout等,會先將他們交給瀏覽器的其他模組去執行,執行完後,會把回調函數放入到taskqueue中。當所有的call stack執行完後再開始執行task queue中的函式。
舉一個簡單的例子:

console.log(1);
setTimeout(function(){console.log(2);}, 0);console.log(3);

我們來看看執行的內部過程
1. 執行第一句,放入call stack中,輸出1
深入了解JS事件循環機制
2. 第一句出棧,執行第二句,由於是非同步執行,交給其他模組。
深入了解JS事件循環機制
3. 執行完後,將回呼函數放入taskqueue中
深入了解JS事件循環機制
4. 執行下一句,同第一步一樣,將語句入堆疊並執行,輸出3
深入了解JS事件循環機制
5. 語句出棧,此時call stack空了。開始執行task queue任務,輸出2
深入了解JS事件循環機制
所以,輸出結果是
深入了解JS事件循環機制
與預想一致。

進階

如果加入了Promise又如何運作呢?
我們知道,Promise的回呼函數不是傳入的,而是使用then來呼叫的。因此,Promise中定義的函數應該是馬上執行的,then才是其回呼函數,放入queue隊列。
在參考的文章中也提到了一個重要的概念:

macro-task包括:script(整體程式碼), setTimeout, setInterval, setImmediate, I/ O, UI rendering。
micro-task包括:process.nextTick, Promises, Object.observe, MutationObserver
 執行順序:函數呼叫堆疊清空只剩下全域執行上下文,然後開始執行所有的micro-task。當所有可執行的micro-task執行完畢之後。迴圈再次執行macro-task中的一個任務佇列,執行完之後再執行所有的micro-task,就這樣一直循環。

再看一個例子:

(function test() {
    setTimeout(function() {console.log(4)}, 0);
    new Promise(function executor(resolve) {
        console.log(1);
        for( var i=0 ; i<10000 ; i++ ) {
            i == 9999 && resolve();
        }
        console.log(2);
    }).then(function() {
        console.log(5);
    });
    console.log(3);})()

具體的過程可以看上面那篇文章。大概過程如下:
1. 遇到setTimeout,交給其他模組執行,執行完後回呼放入macro-task中
2. 遇到Promise,立即執行裡面的function,輸出1。
3. 循環開始,遇到resolve(),修改Promise狀態為fulfill。繼續執行,輸出2。
4. 遇到then,將回呼放入micro-task。
5. 繼續執行,輸出3。
6. call stack執行完畢了。開始執行micro-task中的回呼函數,輸出5。
7. micro-task執行完畢,開始執行macro-task中的回呼函數,輸出4。
8. 結束。

以上是深入了解JS事件循環機制的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn