JS引擎中的線程,事件循環,上下文

 
線程
瀏覽器中有哪些進程呢?
1.瀏覽器進程:瀏覽器的主進程,負責瀏覽器的界面界面顯示,與用戶交互,網址欄輸入、前進、後退,以及頁面的創建和銷燬。
2.渲染進程(瀏覽器內核):默認一個tab頁面一個渲染進程,主要的作用爲頁面渲染,腳本執行,事件處理等。
3.GPU進程:用於3D繪製等,將開啓了3D繪製的元素的渲染由CPU轉向GPU,也就是開啓GPU加速。
4.網絡進程:主要負責頁面的網絡資源加載。
5.插件進程:每種類型的插件對應一個進程,僅當使用該插件時才創建。
6.音頻進程:瀏覽器音頻管理。
 
瀏覽器內核就是在渲染進程中,裏面包含了多個引擎,它們擁有各自的線程。
GUI渲染線程
負責解析html, css。構建DOM樹和RenderObject樹。佈局和繪製。
當頁面元素中的某個dom節點有變化,需要繪製時,此線程就會執行。

JS引擎線程
它裏面有個event loop和一個事件隊列。這2者是JS引擎的核心基礎。
擁有異步處理能力,JS引擎是單線程但可以實現異步併發處理事件,實現異步的基礎是依靠上面的event loop和事件隊列。H5的 Web Worker 標準規定,允許 JavaScript 腳本創建多個線程,但是子線程完全受主線程控制,且不得操作 DOM。所以,這個新標準並沒有改變 JavaScript 單線程的本質。
它與GUI渲染線程互斥,用於處理頁面交互和DOM更新,所以JS引擎線程和GUI渲染線程在處理任務時必須保證按順序串行執行,一個執行另一個就要等待,這樣才能保證每次頁面渲染,更新都是確定的,不存在衝突。所以如果js處理的事件耗時,頁面就會出現卡頓。
JS引擎主要負責處理JS腳本的詞法分析,語法分拆,生成語法樹,代碼執行。內存管理,垃圾回收。

事件觸發線程
監控各種事件的發生,比如用戶的交互事件、頁面DOM渲染完成事件等。當這些事件發生時,事件觸發線程會將回調事件從定時器觸發線程或者異步HTTP請求線程它們的事件隊列中讀取出來,放置到JS引擎的事件隊列中,等待JavaScript引擎的執行。
輔助JS引擎線程管理事件隊列,它和JS引擎線程是平級的關係。它的管理事件隊列體現在將要處理的事件從其他線程隊列中取出放到JS引擎的事件隊列中。

定時器觸發線程
用於專門做定時器計數用的,如果其他線程做這件事,可能會因爲執行耗時任務而錯過按時觸發。
觸發時機是當js引擎執行到setTimeOut, setInternal時,就會調用對應的webAPI,這些系統API內部都是將任務放置到定時器觸發線程中進行處理,在線程中會把定時器事件以key:value的形式保存在event table中 方法名:回調函數 ,當回調時間到時,就將回調函數放置在自己的事件隊列中,併發通知到事件觸發線程,讓事件觸發線程將
事件放置到JS引擎的事件隊列中。

異步HTTP請求線程
主要用於檢測網絡狀態變化,如果檢測到網絡成功回調,則會把保存在自己event table中的回調事件放置到當前線程自己的事件隊列中,然後通知,則會通知時間觸發線程把處理回調函數放置到事件隊列中。,併發通知到事件觸發線程,讓事件觸發線程將
事件放置到JS引擎的事件隊列中。
觸發時機是當js引擎執行到ajax請求時,則會調用webAPI提供的接口,接口內部就會切換到異步HTTP請求線程中做網絡事件的處理。
 
事件循環
 
事件循環主要解決了哪些問題?
1.避免耗時任務阻塞流程
html頁面的加載是串行的,渲染進程解析HTML頁面文件,碰到頁面標籤和css時,交給GUI渲染線程處理,碰到js標籤時,則停止GUI渲染線程開始讓js引擎處理js任務,如果要等耗時任務執行完再執行下面的任務,則卡主了頁面。
2.增加了CPU執行效率
當JS引擎執行時碰到setTimeOut定時器事件,ajax網絡事件時,都會調用webAPI讓系統在專門的子線程進行處理,等到了回到時間,再把回調任務添加到js引擎的任務隊列中,實現了耗時任務的同步執行。串行回調,增加了執行效率。

JS引擎的代碼執行流程
1.JS引擎開始執行代碼。
2.根據代碼中的async,sync 同步、異步標識確定走同步流程還是異步流程。
3.同步流程是運行在JS引擎線程的,異步流程則是使用單獨的線程進行處理,等處理完了將事件回調放置到JS引擎的事件隊列中,讓JS引擎進行執行。
4.當JS引擎執行完任務後會檢查其任務隊列中是否還有待處理的任務,如果有就繼續出來,如果沒有就停止等待。
js引擎存在一個monitoring process進程,它會持續不斷的檢查主線程執行棧是否爲空,一旦檢測到有任務就通知JS引擎取出任務執行。
任務的執行是按照任務進入隊列的順序進行的。任務的執行時間是受上一個任務的執行時長決定的,就像setTimeOut,方法裏設置的是2秒後將回調放入js引擎的事件隊列,但是任務的具體執行時間是不能確定的。

 

宏任務與微任務
setTimeOut, setInterval, async這樣的是宏任務
progress.nextTick, Promise這樣的是微任務,微任務是在執行宏任務的時候產生的,它存在全局上下文中。
宏任務與微任務的執行順序是:宏任務 -> 微任務 -> 宏任務 -> 微任務 -> 空。
先執行宏任務,執行結束後。查看微任務隊列中是否有微任務,有的話就執行,如果在執行微任務的過程中又產生了微任務,那麼這個新的微任務會直接添加到當前執行的微任務隊列。直到微任務隊列中的任務都執行完纔會開啓下一輪宏任務->微任務循環。

 

JS執行上下文
 
JS執行上下文是JS代碼執行的環境,JS代碼的執行一定要在其執行上下文中。
全局執行上下文:瀏覽器中的全局上下文就是window, window是一個對象,全局上下文中的this指向的就是window。
函數執行上下文:每次函數的調用都會產生一個函數上下文,函數上下文內容包括:參數,局部變量的棧空間,堆空間。
上下文的生命週期如下:

 

上下文是一個對象,裏面包含了變量對象VO,作用域鏈scopeChain,this對象。其基本結構如下:
ExecutionContext={
  scopeChain:{},
  VO:{},
  this:{}
}
全局上下文變量對象
globalEC={
   VO:window,
   scopeChain:{},
   this:window
}
函數上下文變量對象
function a(a,b){}
a(1,2)
innerTestEC={
  VO={
    arguments:{0:1,1:2,length:2}
    a:undefined,
    b:undefined
    },// 變量對象
  scopeChain:[VO(innerTest),VO(test),VO(global)],//作用域鏈
  this:{}
}

 


參考文章:
https://juejin.cn/post/6844903512845860872
https://zhuanlan.zhihu.com/p/492563097



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章