理解JavaScript中的Event Loop

Event Loop 是一個很重要的概念,指的是計算機系統的一種運行機制。html

JavaScript語言就採用這種機制,來解決單線程運行帶來的一些問題。node

本文參考C. Aaron Cois的《Understanding The Node.js Event Loop》,解釋什麼是Event Loop,以及它與JavaScript語言的單線程模型有何關係。瀏覽器

想要理解Event Loop,就要從程序的運行模式講起。運行之後的程序叫作"進程"(process),通常狀況下,一個進程一次只能執行一個任務。多線程

若是有不少任務須要執行,不外乎三種解決方法。異步

(1)排隊。由於一個進程一次只能執行一個任務,只好等前面的任務執行完了,再執行後面的任務。async

(2)新建進程。使用fork命令,爲每一個任務新建一個進程。函數

(3)新建線程。由於進程太耗費資源,因此現在的程序每每容許一個進程包含多個線程,由線程去完成任務。(進程和線程的詳細解釋,請看這裏。)oop

以JavaScript語言爲例,它是一種單線程語言,全部任務都在一個線程上完成,即採用上面的第一種方法。一旦遇到大量任務或者遇到一個耗時的任務,網頁就會出現"假死",由於JavaScript停不下來,也就沒法響應用戶的行爲。spa

你也許會問,JavaScript爲何是單線程,難道不能實現爲多線程嗎?線程

這跟歷史有關係。JavaScript從誕生起就是單線程。緣由大概是不想讓瀏覽器變得太複雜,由於多線程須要共享資源、且有可能修改彼此的運行結果,對於一種網頁腳本語言來講,這就太複雜了。後來就約定俗成,JavaScript爲一種單線程語言。(Worker API能夠實現多線程,可是JavaScript自己始終是單線程的。)

若是某個任務很耗時,好比涉及不少I/O(輸入/輸出)操做,那麼線程的運行大概是下面的樣子。

上圖的綠色部分是程序的運行時間,紅色部分是等待時間。能夠看到,因爲I/O操做很慢,因此這個線程的大部分運行時間都在空等I/O操做的返回結果。這種運行方式稱爲"同步模式"(synchronous I/O)或"堵塞模式"(blocking I/O)。

若是採用多線程,同時運行多個任務,那極可能就是下面這樣。

上圖代表,多線程不只佔用多倍的系統資源,也閒置多倍的資源,這顯然不合理。

Event Loop就是爲了解決這個問題而提出的。Wikipedia這樣定義:

"Event Loop是一個程序結構,用於等待和發送消息和事件(a programming construct that waits for and dispatches events or messages in a program.)"

簡單說,就是在程序中設置兩個線程:一個負責程序自己的運行,稱爲"主線程";另外一個負責主線程與其餘進程(主要是各類I/O操做)的通訊,被稱爲"Event Loop線程"(能夠譯爲"消息線程")。

上圖主線程的綠色部分,仍是表示運行時間,而橙色部分表示空閒時間。每當遇到I/O的時候,主線程就讓Event Loop線程去通知相應的I/O程序,而後接着日後運行,因此不存在紅色的等待時間。等到I/O程序完成操做,Event Loop線程再把結果返回主線程。主線程就調用事先設定的回調函數,完成整個任務。

能夠看到,因爲多出了橙色的空閒時間,因此主線程得以運行更多的任務,這就提升了效率。這種運行方式稱爲"異步模式"(asynchronous I/O)或"非堵塞模式"(non-blocking mode)。

這正是JavaScript語言的運行方式。單線程模型雖然對JavaScript構成了很大的限制,但也所以使它具有了其餘語言不具有的優點。若是部署得好,JavaScript程序是不會出現堵塞的,這就是爲何node.js平臺能夠用不多的資源,應付大流量訪問的緣由。

相關文章
相關標籤/搜索