Skip to main content

Command Palette

Search for a command to run...

有關瀏覽器Event loop對於javascript的影響

Published
•1 min read•View as Markdown

首先,參考的技術影片網址如下:

https://www.youtube.com/watch?v=8aGhZQkoFbQ&t=1605s

在講到關於事件循環(event loop)前,必須先行了解到幾個需要知道的技術名詞。

何謂單線程語言(single threaded):

Javascript是屬於一種單線程的語言,因此在執行程式碼的時候會一次只執行一段程式打的片段,而每段程式碼會被推入到所謂的堆疊(stack)中去執行。

何謂堆疊(stack):

Javacript中的執行堆疊(call stack)會記錄程式執行到哪個階段。若是呼叫了函式(Function)的話會添加該Function到堆疊的最上方。當Function執行完畢後,該Function便會從最上方抽離。以下面的程式碼為例:

// 1
function multiply(a, b) {
  return a * b
}

// 2
function square(n) {
  return multiply(n, n)
}

// 3
function printSquare(n) {
  let squared = square(n)
  console.log(squared)
}

// 4
printSquare(4)

執行Function的時候,stack為全域環境的程式。接這printSquare會先被呼叫後進入堆疊的最上方,然後再呼叫了square(),再將其進入stack最上方。而相同的multiply()被呼叫了進來,也會跑到stack最上方。因此變成如下:

multiply(n,n)
square(n)
printSquare(4)
main()

隨後執行完後便一一的抽離堆疊。(參考影片的5:27位置)

非同步處理(Async)

由上面的敘述看到,在call stack中會一段一段的處理程式碼,若是一段程式碼執行過久的話則會造成阻塞(blocking)。這個過程叫同步處理。而非同步處理的時在這個程式執行時,利用別的方式去執行其他的程式碼片段,可以將減少blocking。

那Javascript又是個單線程的語言,要一步一步執行程式碼片段,如何去做到非同步處理?此時就要想到Javascript是在瀏覽器(Browser)下執行的,因此會有個WebAPI提供。將執行較慢的程式先丟入到WebAPI中執行,主程式則是繼續執行其他的工作,因此才造就了看似Javascript可以執行Async的感覺。其範例如下:

console.log('hi')

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

console.log('JSConfEU')

一開始先正常照順序執行後如下:

console.log(‘hi’)
main()
setTimeout()

然而在setTimeout()有設立5秒,結果執行堆疊的部分消失於最上層,反而先行執行最後的console.log。

console.log(‘hi’)
console.log('JSConfEU')
main()

結果帶執行完畢之後,最後才出現setTimeout()的結果。

(以上執行跟程式碼請參考影片11:35的位置)

這個時候的問題就在於瀏覽器裡面的Event loop


何謂Event loop

先前提到Browser有提供所謂的WebAPI的工具,而上述程式碼的setTimeout()便是其中的一個。因此當setTimeout()在執行裡面的Function後,便會從堆疊中移除,並移動到WebAPI裡面執行倒數的功能。然後再推到瀏覽去的工作佇列(task queue),等待進一步的指示。也因為這樣此時Javascript也先同時進行另一個程式。

當stack清空完之後,此時event loop會將task queue的項目依序放入到stack去執行最後的動作。因此上述的程式碼才會print出的順序為:

Hi ⇒ JSConfEU ⇒ there

(圖形概念請參考影片12:50位置)

結語:

在講了這麼一大段的名詞解釋後,最後才將event loop講解了一小段。但是其實這是一個整個脈絡,不先知道因,後面的果就會不曉得如何產生,因此整個理解後,這樣Event loop的扮演的角色才會很清楚了解,其實就是整個執行順序上的問題。