2-1 event loop

可能很多人在寫Javascript時,並不知道他是怎麼被執行的。這個時候可以參考一下jQuery作者John Resig一篇好文章,介紹事件及timer怎麼在瀏覽器中執行:How JavaScript Timers Work。通常在網頁中,所有的Javascript執行完畢後(這部份全部都在global scope跑,除非執行函數),接下來就是如John Resig解釋的這樣,所有的事件處理函數,以及timer執行的函數,會排在一個queue結構中,利用一個無窮迴圈,不斷從queue中取出函數來執行。這個就是event loop。


(除了John Resig的那篇文章,Nicholas C. Zakas的 "Professional Javascript for Web Developer 2nd edition" 有一個試閱本:http://yuiblog.com/assets/pdf/zakas-projs-2ed-ch18.pdf,598頁剛好也有簡短的說明)

所以在Javascript中,雖然有非同步,但是他並不是使用執行緒。所有的事件或是非同步執行的函數,都是在同一個執行緒中,利用event loop的方式在執行。至於一些比較慢的動作例如I/O、網頁render, reflow等,實際動作會在其他執行緒跑,等到有結果時才利用事件來觸發處理函數來處理。這樣的模型有幾個好處:
  1. 沒有執行緒的額外成本,所以反應速度很快
  2. 不會有任何程式同時用到同一個變數,不必考慮lock,也不會產生dead lock
  3. 所以程式撰寫很簡單
但是也有一些潛在問題:
  1. 任一個函數執行時間較長,都會讓其他函數更慢執行(因為一個跑完才會跑另一個)
  2. 在多核心硬體普遍的現在,無法用單一的應用程式instance發揮所有的硬體能力
用NodeJS撰寫伺服器程式,碰到的也是一樣的狀況。要讓系統發揮event loop的效能,就要盡量利用事件的方式來組織程式架構。另外,對於一些有可能較為耗時的操作,可以考慮使用 process.nextTick 函數來讓他以非同步的方式執行,避免在同一個函數中執行太久,擋住所有函數的執行。

如果想要測試event loop怎樣在「瀏覽器」中運行,可以在函數中呼叫alert(),這樣會讓所有Javascript的執行停下來,尤其會干擾所有使用timer的函數執行。有一個簡單的例子,這是一個會依照設定的時間間隔嚴格執行動作的動畫,如果時間過了就會跳過要執行的動作。點按圖片以後,人物會快速旋轉,但是在旋轉執行完畢前按下「delay」按鈕,讓alert訊息等久一點,接下來的動畫就完全不會出現了。

Comments