基礎:
瀏覽器 -- 多進程,每一個tab頁獨立一個瀏覽器渲染進程(瀏覽器內核)javascript
每一個瀏覽器渲染進程是多線程的,主要包括:
GUI渲染線程java
JS引擎線程ajax
注意,GUI渲染線程與JS引擎線程是互斥的,因此若是JS執行的時間過長,這樣就會形成頁面的渲染不連貫,致使頁面渲染加載阻塞。編程
事件觸發線程數組
注意,因爲JS的單線程關係,因此這些待處理隊列中的事件都得排隊等待JS引擎處理(當JS引擎空閒時纔會去執行)promise
定時器觸發線程瀏覽器
注意,W3C在HTML標準中規定,規定要求setTimeout中低於4ms的時間間隔算爲4ms。網絡
異步HTTP請求線程多線程
正文:併發
程序中如今運行的部分和未來運行的部分之間的關係就是異步編程的核心
ajax請求的異步:發出請求時,未來才能得到請求返回結果
—— 應該避免同步ajax請求,瀏覽器UI會被鎖定並阻塞全部用戶交互
異步基於事件循環機制 —— JavaScript引擎只是一個按需執行代碼片斷的環境,而這個需求是由其運行環境決定的:當遇到須要等待某些條件(網絡數據、定時器計時到期等),條件知足後,運行環境纔會把回調函數插入到事件循環隊列中(參考基礎資料 事件觸發線程、定時器線程)
書中提到:ES6精確指定了事件循環的工做細節,在技術上將其歸入了javascript引擎的勢力範圍,不是隻由宿主環境管理,怎麼理解?? 和前文基礎部分對於瀏覽器渲染進程包含的多個線程之間關係有必定出入麼?
異步和並行意義徹底不一樣!!
並行 —— 同步執行 ,對於多線程編程,內存的共享提高了複雜度
異步 —— 交替調度
Javascript是單線程執行,從不跨線程共享數據
var a = 1,b=2 function foo(){ a = a + 1; b = b*2 } function bar(){ a = a * 2; b = b + 1; } // ajax(...)是某個庫中提供的函數 ajax( 'http://some.url.1', foo ); ajax( 'http://some.url.2', bar );
因爲js的單線程執行特性,foo() bar()函數內部的代碼具備原子性
雖然foo() bar()存在競態致使 a,b的最終值並不肯定
但這種不肯定性是在函數執行順序上的(兩個ajax返回的順序)
旨在說明 「併發」 的幾種狀況,在js中看似併發實際是由單線程事件循環機制實現的
均以兩個ajax請求的回調函數內執行不一樣代碼爲例:
ES6引入,任務隊列(job queue) —— 掛在事件循環隊列的每一個tick以後的一個隊列, 在事件循環的每一個tick中,可能出現的異步動做不會添加一個完整的新事件到事件循環隊列中,而是會在當前tick的任務隊列末尾添加一個項目(一個任務)
理論上說,任務隊列可能致使無限任務循環
回調函數是javascript異步的基本單元
這章主要討論回調這種自javascript誕生以來就存在的異步方式存在什麼問題(思惟上的(大腦搞不定)、寫法上的(嵌套、硬編碼)、信任問題(控制反轉)等),以引出下一章對新的異步方式Promise的討論
調用回調過早 調用回調過晚(或不被調用) 調用回調次數過少或過多 未能傳遞所需的環境和參數 吞掉可能出現的錯誤和異常
針對回調的問題能夠用一些特定邏輯來解決:
好比回調傳入兩種:正確、錯誤 或 error-first模式
針對回調過早問題:強制回調封裝
但這些解決方案並不通用、且須要每次重複編寫、難以複用
setTimeout(...)只是保證了回調函數不會在指定時間間隔以前執行,時間間隔以後插入到事件循環隊列中,但此時隊列中可能有多個項目
我的理解:
事件循環 -> 基於事件循環隊列,其維護者不是js引擎,當js引擎執行到須要等待某個條件完成的代碼時(ajax,setTimeout等),會交給當前運行環境執行並提供一個回調函數(運行環境可能使用其餘線程),js引擎繼續執行接下來的代碼;條件知足後,運行環境將回調函數插入到事件循環隊列的末尾,js引擎會從事件循環隊列中獲取代碼執行
任務隊列 -> 首先明確任務隊列的位置:掛在事件循環隊列的每一個tick以後的一個隊列,當出現一個新的任務時,老是掛到當前事件循環tick結尾處!搞清楚如下代碼的執行順序就能初步瞭解任務隊列與事件循環隊列的關係了:
console.log('A'); setTimeout( function(){ console.log('B'); },0) var p = new Promise((resolve, reject)=>{ console.log('C'); return Promise.resolve(console.log('D')); // 嵌套promise }) 輸出順序: A C D B
另外,任務隊列是由js引擎本身控制的 @TODO 瞭解具體實現方式