關於JavaScript如何執行 | 程式學習筆記

Hazel
Apr 3, 2021

“single-threaded”, “event-loop”, “asynchronous”, “callback”是什麼?

Photo by Andrik Langfield on Unsplash

身為程式初學者,程式能順利執行當然是首要目的,於是了解程式執行的邏輯及順序即是one of the important things。不然就會發生許多不如預期的執行結果,例如:

  1. 無法成功抓到需要的變數 >> 因為尚未宣告變數,就要抓取這個不存在的變數,自然抓不到(宣告變數寫在了需要變數的功能的後面...)
  2. 沒有順利渲染出需要的資料 >> 因為從API來的資料還沒跑完,自然沒有資料可以用
  3. 沒有抓到要進行操作的DOM節點 >> 因為抓取的時候,要抓取的DOM節點根本還不存在於HTML文件裡,所以根本沒抓到東西(抓取寫在了渲染資料功能的前面了...)

以上都是這個月實際寫過的Bugs,而這些都是因為不理解JavaScript執行規則執行順序導致的。真的是被同步、不同步搞得團團轉的一個月!

藉由下列影片的介紹,我才比較清楚JavaScript這個程式語言到底是如何運作的!

  • 首先,JavaScript是一個single-threaded 單執行緒的程式語言

簡單來說,就是它只有一個時間軸,一次只能做一件事,做完才能在做下一件事。也就是說它一次只能執行一段程式碼,而程式碼會在stack中執行,stack就像JavaScript的工作區。

執行的堆疊(call stack), picture from https://youtu.be/8aGhZQkoFbQ?t=344

一段程式碼的執行可能會需要另一段程式碼的結果,所以會在stack陸續堆疊起來,然後在跑完或return後抽離,陸續功成身退直到stack清空。

若是函式(function)沒寫好,return一樣的function.就會一直堆疊上去出現跟無限迴圈一樣無法結束的error。

接著,單執行緒也意味著,如果有某一段程式碼需要執行一段較長的時間,或等待一段時間,後續的程式碼就無法執行,也就是會出現卡住的狀態。例如:跟其他資料庫伺服器請求資料時,如果是同步處理(synchronous)的狀態下,就必須等請求的資料都傳回來了,才能進行後續的程式碼。發生在瀏覽器的話,就是在請求資料的時候,會出現loading的畫面,一直run直到資料都拿到了才能做其他事(看後續的圖片、文字...)

  • 用非同步(asynchronous)解決卡住

setTimeout及像其他伺服器請求資料的這些功能其實並不是JavaScript的原有功能,而是瀏覽器提供的APIs,所以可以在WebAPI進行非同步的處理,也就是當執行緒輪到他們時,他們會直接被移至WebAPI(另一個時間軸)執行。完成時,在被叫回來,因此又名callback function。

callback function, picture from https://youtu.be/XzXIMZMN9k4?t=161

那怎麼回來?如果隨時隨地完成,即隨時隨地回來,不就會打亂call stack的執行?

  • event-loop(事件循環)的功用

實際上,這些callback function在跑完自己的任務後,會先按順序排進被稱作工作佇列(task queue)的地方,或也可以說是callback queue。

然後,event-loop就像是call stack和task queue中間的調停監視者,在確認call stack目前是清空的狀態,就會陸續把task queue裡完成的callback function傳回call stack執行。

當setTimeout設定等待0秒時:

function setTimeoutTest() {console.log(1)setTimeout(() => {console.log(2)}, 0)console.log(3)}setTimeoutTest()
// 1
// 3
// 2

--

--

Hazel

Web & Software Developer 🇹🇼 Taiwanese Explorer @MyLifeAdventure ICS Student @CamosunCollege