在瀏覽器當中執行 JavaScript 最主要關鍵在於瞭解上次提到的執行環境,以及接下來提到執行環境的堆疊(Execution Context Stack 或稱 Call Stack)與任務循環(Event Loop)機制。
Execution Context Stack
每呼叫一次函式就會創立一個執行環境(Execution Context),並且在執行完畢前又有新的執行環境時就會堆疊起來,而這種執行環境中的堆疊又稱呼叫堆疊(Call Stack)顧名思義,其資料結構是一個堆疊(Stack),而這種資料結構處理方式就是後入先出(LIFO,Last in First out):
例如當我們執行下面程式碼時:
1 | function func1 () { |
在呼叫堆疊中看起來就像這樣:
一進入 JavaScript 前會執行一個主程式函式來包裹。
接著執行 func1()
函式,進入 func1()
函式後執行 func2()
函式。
在執行 console.log('func2')
完後,func2()
函式會從 stack 中移除。
執行 console.log('func1')
,func1()
函式會從 stack 中移除。
最後整段程式碼都執行完畢時,便把 main
也拋出 stack。
這就是 Execution Context Stack(Call Stack)呼叫堆疊的運作方式,也就是為何大家會說 JavaScript 是 單執行緒(single thread) 的原因。
但以上的例子都只有同步(synchronous)的情況,如果遇到像是 setTimeout() 等 Web APIs 與需要藉由 Ajax 取得資料的非同步(Asynchronous)情況時,這時候就輪到 Event Loop 與 Job Queue 上場了。