js事件循環機制辨析
?對於新接觸js語言的人來說,最令人困惑的大概就是事件循環機制了。最開始這也困惑了我好久,花了我幾個月時間通過書本,打代碼,查閱資料不停地漸進地理解他。接下來我想要和大家分享一下,雖然可能有些許錯誤的地方,希望大家不吝賜教,感謝感謝。
?這是所涉及的知識點:
- 觀察者模式
- js的事件循環機制
- js事件循環機制優缺點及與多線程的比較
觀察者模式
?js的事件循環機制是基於觀察者模式的,而跟觀察者模式相對應的是輪詢,我們先來說說輪詢的原理。
?我們將輪詢映射在現實世界中即為:B不停到A的房間觀察房間裏是否有人,從而知道A是否回來。
?但顯然,這是效率極低的,我們回到代碼層面上。B線程使用while(true){觀察A的房間,當A在房間內時退出循環}來做到輪詢。但是,這樣B線程就被堵塞
?同樣的,我們來將觀察者模式映射到現實世界中:B在自己房間做自己的事情,不再不停地到A的房間看他是否回來,而是當A回到自己房間時,打電話通知B他回來了,B再去房間找A玩。
?該模式最大的優勢就是:B可以在等待A回房間的期間,做自己的事情。回到代碼層面上,使用觀察者模式後,B線程不再被堵塞,A回到房間的信息不再需要B通過循環來同步地監聽,而是A用消息傳給B線程,B再根據這個消息來執行當A回到房間後應該執行的操作。
?其實當理解了觀察者模式的大體流程就已經能夠理解js的事件循環機制了。但了解得深入些也沒有壞處。接下來我們來用js代碼來模擬出一個簡易的觀察者模式。
代碼如下:
var b = {
process_a:mes=>{
console.log(‘剛剛A發了 %s 的信息,所以我知道A回來了,我該去他房間找他玩了。‘,mes)
}
}
function A(b){
var mes_a = ‘我是A,我回來了‘
b.process_a(mes_a)
}
A(b)
?結果如下:
?如果大家對同步,異步,堵塞,非堵塞的概念有不理解的地方的話,可以看我的 同步,異步,堵塞,非堵塞,並發 辨析。
事件循環機制
?事件循環機制的核心就是觀察者模式。我先給大家描述一遍程序執行的流程。
- js程序進入線程,函數入棧,當遇到同步代碼的時候就順序執行,遇到異步代碼時,把異步任務拋給WebAPIs執行,然後繼續執行接下來的同步代碼,直到棧為空。(如若大家對函數棧不了解的話可以看下我的 棧,堆辨析及使用)
- 在步驟1進行的同時,WebAPIs執行異步任務,當執行完一個異步任務就將其對應的回調函數放入任務隊列(Callback Queue)中等待。
- WebAPIs是由C++實現的瀏覽器創建的線程,處理諸如DOM事件,http請求,定時器等異步任務。
- 當執行棧為空時,從Callback Queue中取出隊列頭放入執行棧中,回到第一步。
?給大家一個我畫的圖,方便理解。
?不過大家可能會疑惑,事件循環機制跟觀察者模式哪有什麽關系?其實是這樣的,在第2步中我寫道
當執行完一個異步任務就將其對應的回調函數放入任務隊列(Callback Queue)中。
?但我們是如何判斷這個異步任務執行完了呢——觀察者模式。任務隊列是觀察者,WebAPIs是被觀察者,觀察者要求被觀察者當發生執行完異步任務這一事件時,通知他執行完了,並將該事件對應的回調函數傳過來。
js事件循環機制優缺點及與多線程的比較
?通過事件循環機制,我們就可以實現代碼的異步,從而不會堵塞線程。
?通過這一特性,
- js在IO上有著卓越的表現,因為IO操作不再會堵塞住線程。
- 可以做到高並發。稍微解釋一下為什麽能夠高並發——當同時有多個任務要執行,js將他一一排列起來,然後按順序執行,這樣cpu就不會因為同時要處理的工作太多而負載過大。
?樸靈在《深入淺出nodeJS》中說道:
石器時代:同步。青銅時代:復制線程。白銀時代:多線程。黃金時代:事件驅動。
?不過我不敢說事件驅動就是比多線程好,但他確實沒有多線程的這些惱人的缺陷。
- 如果有大量的線程,會影響性能,因為操作系統需要在線程之間不停進行上下文切換。
- 通常數據是多個線程共享的,需要上鎖,同時又要防止出現死鎖現象。
- IO會堵塞住一個線程。
?但同時的,js也有他的缺陷。
- 不適合cpu密集型。也解釋一下——如一段代碼需要非常大量的計算量,以至於他長時間地占著線程,這就堵塞了,後繼的同步代碼及異步代碼都無法執行。不過,html5推出了web worker,可以有效地解決這一缺陷,在本章不表,後面我會專門寫一篇文章來講他。
- 只能使用一個線程,無法充分利用計算機的多核cpu。
- 可靠性低,一旦一個環節崩潰則整個程序全部崩潰。
?沒有一項技術是絕對完美的,但我們要清楚他的優缺點及原因,從而能夠充分利用其優點,同時規避其缺點甚至通過自己的方式解決其缺點。
參考資料
- Advantages and Disadvantages of a Multithreaded/Multicontexted Application: https://docs.oracle.com/cd/E13203_01/tuxedo/tux71/html/pgthr5.htm
- https://www.hostreview.com/blog/160311-the-pros-and-cons-of-using-nodejs: https://www.hostreview.com/blog/160311-the-pros-and-cons-of-using-nodejs
- 理解事件循環與任務隊列:https://www.jianshu.com/p/e865c3a7ba10
js事件循環機制辨析