摘要:異步請求線程在在連接后是通過瀏覽器新開一個線程請求將檢測到狀態變更時,如果設置有回調函數,異步線程就產生狀態變更事件,將這個回調再放入事件循環隊列中。
基礎:
瀏覽器 -- 多進程,每個tab頁獨立一個瀏覽器渲染進程(瀏覽器內核)
每個瀏覽器渲染進程是多線程的,主要包括:
GUI渲染線程
JS引擎線程
也稱為JS內核,負責處理Javascript腳本程序。(例如V8引擎)
JS引擎線程負責解析Javascript腳本,運行代碼。
JS引擎一直等待著事件循環隊列中任務的到來,然后加以處理,一個Tab頁(renderer進程)中無論什么時候都只有一個JS線程在運行JS程序
注意,GUI渲染線程與JS引擎線程是互斥的,所以如果JS執行的時間過長,這樣就會造成頁面的渲染不連貫,導致頁面渲染加載阻塞。
事件觸發線程
歸屬于瀏覽器而不是JS引擎,用來控制事件循環(可以理解,JS引擎自己都忙不過來,需要瀏覽器另開線程協助)
當JS引擎執行代碼塊如setTimeOut時(也可來自瀏覽器內核的其他線程,如鼠標點擊、AJAX異步請求等),會將對應任務添加到事件線程中
當對應的事件符合觸發條件被觸發時,該線程會把事件添加到事件循環隊列的隊尾,等待JS引擎的處理
注意,由于JS的單線程關系,所以這些待處理隊列中的事件都得排隊等待JS引擎處理(當JS引擎空閑時才會去執行)
定時器觸發線程
setInterval與setTimeout所在線程
瀏覽器定時計數器并不是由JavaScript引擎計數的,(因為JavaScript引擎是單線程的, 如果處于阻塞線程狀態就會影響記計時的準確)
因此通過多帶帶線程來計時并觸發定時(計時完畢后,添加到事件循環隊列中,等待JS引擎空閑后執行)
注意,W3C在HTML標準中規定,規定要求setTimeout中低于4ms的時間間隔算為4ms。
異步HTTP請求線程
在XMLHttpRequest在連接后是通過瀏覽器新開一個線程請求
將檢測到狀態變更時,如果設置有回調函數,異步線程就產生狀態變更事件,將這個回調再放入事件循環隊列中。再由JavaScript引擎執行。
正文:
異步 分塊程序、事件循環、并行程序中現在運行的部分和將來運行的部分之間的關系就是異步編程的核心
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請求的回調函數內執行不同代碼為例:
非交互: 兩個并發任務間彼此獨立不相關,這時不確定性是完全可以接受的
交互: 并發任務間彼此通過作用域或者DOM間接交互,比如都向數組中插入一條數據,這時數組中條目的順序就和并發任務執行順序有關了,在需要保證正確交互順序的場景需要加入協調代碼
協作: 并發協作,將一個會長期執行的任務分割為多個步驟或多批任務執行,以便占領事件循環隊列太久時間,如setTimeout(...0)進行異步調度
任務隊列ES6引入,任務隊列(job queue) —— 掛在事件循環隊列的每個tick之后的一個隊列, 在事件循環的每個tick中,可能出現的異步動作不會添加一個完整的新事件到事件循環隊列中,而是會在當前tick的任務隊列末尾添加一個項目(一個任務)
理論上說,任務隊列可能導致無限任務循環
回調函數是javascript異步的基本單元
這章主要討論回調這種自javascript誕生以來就存在的異步方式存在什么問題(思維上的(大腦搞不定)、寫法上的(嵌套、硬編碼)、信任問題(控制反轉)等),以引出下一章對新的異步方式Promise的討論
給異步方法async傳入continuation,當異步方法async結束時主動調用continuation執行
事實上async并不關心其結束對其他模塊有什么影響,但使用回調的方式,async在結束時必須主動調用所有傳入的continuation
如果有數個異步任務需要鏈式執行,代碼寫法上很容易形成callback hell,但這不是重點,即使把嵌套寫法解開寫成多個函數調用的方式,也同樣不易于閱讀;而且還有另一個問題,當鏈式回調中一個斷掉時,如何處理錯誤情況?需要硬編碼在各個函數中進行處理,代碼復雜度大大增加
另外還有一個信任問題,有些情況下異步任務是第三方提供,使用回調其實就是將代碼控制器交給了第三方處理——控制反轉
調用回調過早 調用回調過晚(或不被調用) 調用回調次數過少或過多 未能傳遞所需的環境和參數 吞掉可能出現的錯誤和異常
針對回調的問題可以用一些特定邏輯來解決:
比如回調傳入兩種:正確、錯誤 或 error-first模式
針對回調過早問題:強制回調封裝
但這些解決方案并不通用、且需要每次重復編寫、難以復用
幾個問題為什么setTimeout(...)定時器可能精度不高?
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 了解具體實現方式
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/93687.html
摘要:這時候控制臺看到的是對象的快照,然而點開看詳情的話是這段代碼在運行的時候,瀏覽器可能會認為需要把控制臺延遲到后臺,這種情況下,等到瀏覽器控制臺輸出對象內容時,可能已經運行,因此會在點開的時候顯示,這是的異步化造成的。 本書屬于基礎類書籍,會有比較多的基礎知識,所以這里僅記錄平常不怎么容易注意到的知識點,不會全記,供大家和自己翻閱; 上中下三本的讀書筆記: 《你不知道的JavaScri...
摘要:寫在前面這一章的順序對于未接觸過使用過的童鞋而言略抽象了,前邊幾章主要為了說明和之前的異步方式相比有什么優勢和它能解決什么問題,后邊才詳解的設計和各種場景下如何使用。建議先了解和簡單使用過后再閱讀,效果更佳。 寫在前面:Promise這一章的順序對于未接觸過使用過Promise的童鞋而言略抽象了,前邊幾章主要為了說明Promise和之前的異步方式相比有什么優勢和它能解決什么問題,后邊才...
摘要:注此讀書筆記只記錄本人原先不太理解的內容經過閱讀你不知道的后的理解。作用域及閉包基礎,代碼運行的幕后工作者引擎及編譯器。 注:此讀書筆記只記錄本人原先不太理解的內容經過閱讀《你不知道的JS》后的理解。 作用域及閉包基礎,JS代碼運行的幕后工作者:引擎及編譯器。引擎負責JS程序的編譯及執行,編譯器負責詞法分析和代碼生成。那么作用域就像一個容器,引擎及編譯器都從這里提取東西。 ...
摘要:閉包在循環中的應用延遲函數的回調會在循環結束時才執行事實上,當定時器運行時即使沒給迭代中執行的是多有的回調函數依然是在循環結束后才會被執行,因此會每次輸出一個出來。 閉包在循環中的應用 延遲函數的回調會在循環結束時才執行;事實上,當定時器運行時即使沒給迭代中執行的是 setTime(..., 0),多有的回調函數依然是在循環結束后才會被執行,因此會每次輸出一個6出來。 for(var...
摘要:有種內置類型,分別是除對象之外,其他統稱為基本類型。另一個需要注意的是數組確切地說,數組也是的一個子類型我們可以通過下面的方法檢查變量是不是數組處理未聲明的變量時,會返回這是因為有一個特殊的安全防范機制。 js有7種內置類型,分別是undefined null boolean string number symbol object除對象之 Object 外,其他統稱為基本類型。符號 ...
閱讀 2241·2023-04-26 01:50
閱讀 706·2021-09-22 15:20
閱讀 2579·2019-08-30 15:53
閱讀 1585·2019-08-30 12:49
閱讀 1704·2019-08-26 14:05
閱讀 2700·2019-08-26 11:42
閱讀 2298·2019-08-26 10:40
閱讀 2587·2019-08-26 10:38