理解 Javascript 裡的 event loop 運作

Taylor
5 min readJun 25, 2020

--

本篇內容整理 Philip Roberts 演講影片, 圖片擷取影片片段
https://www.youtube.com/watch?time_continue=195&v=8aGhZQkoFbQ&feature=emb_logo

Single thread
Javascript 是個單線程(single thread)的語言, 也就是單一時間點只能執行一個指令, 無法執行多個

Stack
程式語言在執行時, 會按照執行順序把內容放到 stack
比如下圖, 首先進入 stack 是全域程式環境 main(), 接著是 printSquare(4), printSquare 裡面呼叫 square(n), 因此 square(n) 接著放進 stack, 以此類推

而 stack 行為是 First in last out, 執行順序
multiply(n, n) -> square(n)->printSquare(4)->main()
執行後 stack 會跟著清空

Blocking
當碰到需要等待一段時間程式碼時, 像是卡住一段時間, 這種現象就做 “blocking”. 如下程式碼

// pseudo code
var foo = $.getSync('//foo.com')
var bar = $.getSync('//bar.com')
var qux = $.getSync('//qux.com')

console.log(foo)
console.log(bar)
console.log(qux)

執行 getSync() 時需要等待些時間, 這段時間瀏覽器無法做任何動作, 必須等到當下程式碼結束才能執行下個動作

非同步處理 (Async Callback)
為了解決上面 block 問題, 可以透過非同步處理方式搭配 callback

console.log('hi')

setTimeout(function () {
console.log('there')
}, 5000)

console.log('JSConfEU')
一開始先處理 hi, 接著處理 setTimeout(), timeout 需要 5 秒先把 setTimeout() 放在其他位置
接著處理 JSConfEU
5 秒過後, setTimeout 指令從別的暫存地方移到 stack, 顯示 there

那 setTimeout() 被暫時放在哪邊呢 ?

Concurrency and Event Loop
Javascript 在同個時間只能執行一件事, 不過瀏覽器提供許多 API, 讓我們可以用 event loop 搭配非同步方法同時 (concurrent) 處理許多事

在上面 Async 裡說到用 setTimeout 方式實行非同步, setTimeout 是瀏覽器提供的 API

setTimeout 中 callback (簡稱 cb) 會被放在 webapis 中
當 timer 時間到, 會先放到 task queue 中

當 stack 中沒有其他指令, 這時輪到 event loop 功能登場, 它會把 task queue 中第一個指令給 stack (queue 跟 stack 相反, First in first out)

stack 中沒有其他指令時, 從 task queue 中拿取指令, cb 回到 stack 中

setTimeout 0
假設上面 case 換成設定 setTimeout 0 會發生什麼事呢 ?

console.log('hi')

setTimeout(function () {
console.log('there')
}, 0)

console.log('JSConfEU')

預想上 timeout 0 表示 0 秒後啟動, 執行應該是 hi -> there -> JSConfEU

但依照上面邏輯, 即便我們只是等 0 秒, cb 依樣會放到 task queue 中, 等到 stack 指令執行完才會執行 setTimeout 裡的內容, 所以正確執行為
hi -> JSConfEU -> there

--

--

Taylor
0 Followers

CS engineer. Like photograph and cocktail in weekend.