對於新接觸js語言的人來講,最使人困惑的大概就是事件循環機制了。最開始這也困惑了我很久,花了我幾個月時間經過書本,打代碼,查閱資料不停地漸進地理解他。接下來我想要和你們分享一下,雖然可能有些許錯誤的地方,但願你們不吝賜教,感謝感謝。html
這是所涉及的知識點:html5
js的事件循環機制是基於觀察者模式的,而跟觀察者模式相對應的是輪詢,咱們先來講說輪詢的原理。node
咱們將輪詢映射在現實世界中即爲:B不停到A的房間觀察房間裏是否有人,從而知道A是否回來。web
但顯然,這是效率極低的,咱們回到代碼層面上。B線程使用while(true){觀察A的房間,當A在房間內時退出循環}來作到輪詢。可是,這樣B線程就被堵塞住了,除非退出該循環,不然沒法執行接下來的同步代碼及異步代碼。這對於單線程語言是徹底沒法接受的,因此咱們來看看觀察者模式,他是否會堵塞線程。瀏覽器
一樣的,咱們來將觀察者模式映射到現實世界中:B在本身房間作本身的事情,再也不不停地到A的房間看他是否回來,而是當A回到本身房間時,打電話通知B他回來了,B再去房間找A玩。多線程
該模式最大的優點就是:B能夠在等待A回房間的期間,作本身的事情。回到代碼層面上,使用觀察者模式後,B線程再也不被堵塞,A回到房間的信息再也不須要B經過循環來同步地監聽,而是A用消息傳給B線程,B再根據這個消息來執行當A回到房間後應該執行的操做。併發
其實當理解了觀察者模式的大致流程就已經可以理解js的事件循環機制了。但瞭解得深刻些也沒有壞處。接下來咱們來用js代碼來模擬出一個簡易的觀察者模式。
代碼以下:oracle
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)
結果以下:
異步
若是你們對同步,異步,堵塞,非堵塞的概念有不理解的地方的話,能夠看個人 同步,異步,堵塞,非堵塞,併發 辨析。函數
事件循環機制的核心就是觀察者模式。我先給你們描述一遍程序執行的流程。
給你們一個我畫的圖,方便理解。
不過你們可能會疑惑,事件循環機制跟觀察者模式哪有什麼關係?實際上是這樣的,在第2步中我寫道
當執行完一個異步任務就將其對應的回調函數放入任務隊列(Callback Queue)中。
但咱們是如何判斷這個異步任務執行完了呢——觀察者模式。任務隊列是觀察者,WebAPIs是被觀察者,觀察者要求被觀察者當發生執行完異步任務這一事件時,通知他執行完了,並將該事件對應的回調函數傳過來。
經過事件循環機制,咱們就能夠實現代碼的異步,從而不會堵塞線程。
經過這一特性,
樸靈在《深刻淺出nodeJS》中說道:
石器時代:同步。青銅時代:複製線程。白銀時代:多線程。黃金時代:事件驅動。
不過我不敢說事件驅動就是比多線程好,但他確實沒有多線程的這些惱人的缺陷。
但同時的,js也有他的缺陷。
沒有一項技術是絕對完美的,但咱們要清楚他的優缺點及緣由,從而可以充分利用其優勢,同時規避其缺點甚至經過本身的方式解決其缺點。