總結javascript基礎概念(二):事件隊列循環

主要問題:node

一、JS引擎是單線程,如何完成事件循環的?
二、定時器函數爲何計時不許確?
三、回調與異步,有什麼聯繫和不一樣?
四、ES6的事件循環有什麼變化?Node中呢?
五、異步控制有什麼難點?有什麼解決方案?

2、事件隊列循環web

(一)、瀏覽器線程ajax

JavaScript引擎是基於事件驅動單線程運行的,瀏覽器不管在何時都只且只有一個線程在運行JavaScript程序,等待着任務隊列中任務的到來,而後加以處理。api

瀏覽器的內核是多線程的,它們在內核控制下相互配合協做,一個瀏覽器至少實現三個常駐線程:JavaScript引擎線程,GUI渲染線程,瀏覽器事件線程。數組

GUI渲染線程負責渲染瀏覽器界面,當界面須要重繪(Repaint)或因爲某種操做引起迴流(Reflow)時,該線程就會執行。GUI渲染線程與JavaScript引擎是互斥的,當JavaScript引擎執行時GUI線程會被掛起,GUI更新會被保存在一個隊列中等到JavaScript引擎空閒時當即被執行。因此渲染操做的消耗特別大。promise

clipboard.png

(一)、事件類型與隊列
事件循環:引擎會建立一個相似於 while (true) 的無限循環,每執行一次循環體的過程稱之爲 Tick。每次 Tick 的過程就是查看是否有待處理事件,若是有則取出相關事件及回調函數放入執行棧中由主線程執行。待處理的事件會存儲在一個任務隊列中,也就是每次 Tick 會查看任務隊列中是否有須要執行的任務。瀏覽器

任務隊列:異步操做會將相關回調添加到任務隊列中。而不一樣的異步操做添加到任務隊列的時機也不一樣,如 onclick, setTimeout, ajax 處理的方式都不一樣,這些異步操做是由瀏覽器內核的 webcore 來執行的,webcore 包含上圖中的3種 webAPI,分別是 DOM Binding、network、timer模塊。網絡

onclick 由瀏覽器內核的 DOM Binding 模塊來處理,當事件觸發的時候,回調函數會當即添加到任務隊列中。
setTimeout 會由瀏覽器內核的 timer 模塊來進行延時處理,當時間到達的時候,纔會將回調函數添加到任務隊列中。多線程

js定時器不許確的緣由:
一、異步函數的回調執行會阻塞下一個循環tick。二、瀏覽器的時間精度不一。

ajax 則會由瀏覽器內核的 network 模塊來處理,在網絡請求完成返回以後,纔將回調添加到任務隊列中。框架

主線程:JS 只有一個線程,稱之爲主線程。而事件循環是主線程中執行棧裏的代碼執行完畢以後,纔開始執行的。因此,主線程中要執行的代碼時間過長,會阻塞事件循環的執行,也就會阻塞異步操做的執行。只有當主線程中執行棧爲空的時候(即同步代碼執行完後),纔會進行事件循環來觀察要執行的事件回調,當事件循環檢測到任務隊列中有事件就取出相關回調放入執行棧中由主線程執行。

在這個過程提升頁面響應速度的方式:減小主線程同步代碼的數量,
將不重要的代碼轉移到事件循環階段執行

(三)、ES6的任務隊列
對事件隊列進行了改造,使得異步回調能夠更早的執行,每一個tick間隙都會優先執行任務隊列,不用排到事件隊列的末尾。一道必考題,看一下執行順序:

clipboard.png
Promise實例具備三種狀態:等待,決議,拒絕。由此產生的異步事件執行會做爲任務隊列掛在當前tick循環的末尾執行。

(四)、Nodo中的事件循環
JS引擎的事件循環都須要宿主環境提供隊列維護,Node脫離了瀏覽器,用到了不一樣的方式和底層系統作交互。

觀察者:引擎在每一個循環過程當中詢問觀察者是否有要處理的事件。

在Window下,觀察者基於IOCP監聽事件的完成狀況;在*nix下基於多線程建立。

在node增長了異步執行的api,如process。nextTick()和setImmiediate。
process。nextTick()的回調函數保存在一個數組中,setImmiediate則是保存在一個鏈表中。
在每輪循環中,會將nextTick的數組中回調函數所有執行完,而後執行一個setImmiediate鏈表中的回調。

(五)、異步事件的處理
異步事件的處理過程當中有執行時間、順序不肯定,回調地獄,錯誤難捕獲定位等問題。

一、jQuery的 Deferred隊列模塊
JQ在 Deferred隊列模塊的基礎上,模擬實現了promise類似的方法。能夠作到鏈式回調,延遲訪問。
二、ES6 Promise
promise實例決議後就不可更改,解決了信任問題。可使用鏈式回調,隨時訪問異步事件的狀態。相比以前要將回調交給另外一方控制,promise能夠將回調的執行控制在本身的邏輯中。至此仍未從實質上解決異步。
三、Generator
生成器函數實現了真正的異步控制,能夠切換執行環境,並在執行環境之間傳遞變量,實現協做的函數線程。
著名的co模塊,結合使用Promise和Generator實現了異步流程的同步編碼形式。
四、async 函數
ES2017 標準引入了 async 函數,使得異步操做變得更加方便。就是 Generator 函數的語法糖。
Node框架Koa採用了最新的async處理異步流程,使得編碼更加簡潔流暢。

推薦參考書:

《深刻淺出NodeJS》
《jQuery技術內幕》
《Webkit技術內幕》
《你不知道的JavaScript》
相關文章
相關標籤/搜索