event loop(事件循環) 一 深入理解

如果面試官問你 JS中的event loop是什么?我相信大多數人都能答出來JS是單線程語言,只有一個主線程執行,執行棧,同步、異步之類。但是,這樣的理解只是淺層的,如果面試官要你再深入解釋,我相信大多數人都卡住了,不知道還能解釋什么,那么,問題來了,這種情況怎么辦?

來看這篇文章,看完了你就知道怎么辦了。

JS頁面的任務不僅可以按照同步異步來分,也可以分為macro-taskmicro-task

macro-task都有:包括整體代碼script,setTimeout,setInterval
micro-task都有:Promise,process.nextTick

頁面初始化時,不同的任務會進入到不同的 Event Queue(事件隊列)

初始化時,會執行所有代碼,將setTimeout等加入到macro-task的事件列表,將Promise等加入到micro-task事件列表。
遇到立即執行的代碼,則立即執行,之后,會將事件列表中所有的micro-task都執行完畢。

第一輪事件循環結束。

第二輪事件循環開始,拿出第一輪中第一個放入macro-task列表中的事件開始執行完畢

第二輪事件循環結束。

第三輪循環開始,拿出第一輪中第二個放入macro-task列表中的事件開始執行完畢

第三輪事件循環結束。

就像上面這樣,反復執行,即事件循環

看了上面的解釋,接下來,我們來看一個例子:

console.log('1');

setTimeout(function() {
    console.log('2');
    process.nextTick(function() {
        console.log('3');
    })
    new Promise(function(resolve) {
        console.log('4');
        resolve();
    }).then(function() {
        console.log('5')
    })
})

process.nextTick(function() {
    console.log('6');
})

new Promise(function(resolve) {
    console.log('7');
    resolve();
}).then(function() {
    console.log('8')
})

setTimeout(function() {
    console.log('9');
    process.nextTick(function() {
        console.log('10');
    })
    new Promise(function(resolve) {
        console.log('11');
        resolve();
    }).then(function() {
        console.log('12')
    })
})

我們按照上面的理論來分析這段代碼:

首先,進入到第一輪事件循環:

遇到 console.log('1') 輸出 '1'

遇到 setTimeout,將其回調函數加入到 macro-task 事件列表,記為 setTimeout1

遇到 process.nextTick,將其回調函數加入到 micro-task 事件列表,記為 process1

遇到 new Promise,立即執行,輸出 ** '7'**,then被分發到 micro-task 事件列表,記為 then1

遇到 setTimeout 將其回調函數加入到 macro-task 事件列表,記為 setTimeout2

執行到這里,我們來數數第一輪事件循環中的任務列表:

macro-task:setTimeout1,setTimeout2

micro-task:process1, then1

將列表中所有的 micro-task 執行完畢,輸出 '6','8'

第一輪事件循環正式結束。

第二輪事件循環開始:

這時,第一輪輸出結果是 '1','7','6','8'

macro-task 中,拿出第一個進入的事件,即setTimeout1,將其推入到執行棧開始執行

先輸出:'2'

遇到 process.nextTick,將其回調函數加入到 micro-task 事件列表,記為 process2

遇到 new Promise, 立即執行,輸出 ** '4'**,將then回調函數加入到 micro-task 事件列表,記為 then2

執行到這里,我們數數第二輪事件循環中的任務列表:

macro-task:setTimeout1

micro-task:process2,then2

將列表中所有的 micro-task 執行完畢,輸出:'3', '5'

第二輪事件循環結束

第三輪事件循環開始,前兩輪輸出為:'1','7','6','8','2','4','3', '5'

在 macro-task 中,拿出第二個進入的事件,即setTimeout2,將其推入到執行棧開始執行

先輸出:'9'

遇到 process.nextTick,將其回調函數加入到 micro-task 事件列表,記為 process3

遇到 new Promise, 立即執行,輸出 '11',將then回調函數加入到 micro-task 事件列表,記為 then3

執行到這里,我們數數第三輪事件循環中的任務列表:

macro-task:setTimeout2

micro-task:process3,then3

將列表中所有的 micro-task 執行完畢,輸出:'10', '12'

第三輪事件循環結束。

如果還有第四輪,第五輪,則循環上面的步驟,這樣的循環,即事件循環

總結執行結果:'1','7','6','8','2','4','3','5','9','11','10','12'

好,寫完收工,等待下班去吃大餐。

原文作者寫的更好,大家可以看看 https://juejin.im/post/59e85eebf265da430d571f89

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。