JS執行機制(學習筆記)
程序和執行緒:
程序是一個工廠,工廠之間相互獨立
執行緒是工廠中的工人,多個工人(執行緒)協作完成任務
工廠內有一個或多個工人-工人之間共享空間
工廠的資源->系統分配的記憶體(獨立的一塊記憶體)
工廠之間相互獨立->程序之間相互獨立
多個工人協作完成任務->多個執行緒在程序中協作完成任務
工廠內有一個或多個工人->一個程序由一個或多個執行緒組成
工人之間共享空間->同一程序下的各個執行緒之間共享程式的記憶體空間
程序是cpu資源分配的最小單位(系統會給它分配記憶體)
單執行緒和多執行緒,都是指在一個程序內的單和多
瀏覽器是多程序
瀏覽器之所以能夠執行,是因為系統給它的程序分配了資源(cpu,記憶體)
每開啟一個tab頁,就相當於建立了一個獨立的瀏覽器程序
注意:開啟多個tab頁時,瀏覽器可能合併程序
瀏覽器包含程序:
Browser程序:瀏覽器的主程序,只有一個。作用:
負責瀏覽器介面顯示,與使用者互動。如前進後退
負責各個頁面的管理,建立和銷燬其他程序
將Renderer程序得到的記憶體中的Bitmap繪製到使用者介面上
網路資源的管理,下載等
第三方外掛程序:每種型別的外掛對應一個程序,僅當使用該外掛時才建立
GPU程序:最多一個,用於3D繪製等
瀏覽器渲染程序(瀏覽器核心)(Renderer程序,內部是多執行緒的):預設每個tab頁一個程序,互不影響。主要作用:
頁面渲染,指令碼執行,事件處理等
在瀏覽器中開啟一個網頁相當於新起了一個程序(程序內有自己的多執行緒)
普通前端操作渲染程序(render程序)
主要常駐執行緒:
GUI渲染執行緒:
渲染瀏覽器介面,解析HTML,CSS,構建DOM樹和RenderObject樹,佈局和繪製等。
重繪頁面會引發迴流時
注意:GUI渲染執行緒與JS引擎執行緒是互斥的,GUI更新會被儲存在一個佇列中等到JS引擎空閒時執行
JS引擎執行緒:
處理JavaScript指令碼(如V8引擎)
解析JavaScript指令碼,執行程式碼。
一個tab頁中無論什麼時候都只有一個JS執行緒在執行JS程式,所以時間都是排隊等JS執行緒處理
事件觸發執行緒:
歸屬於瀏覽器,用來控制事件迴圈
執行setTimeOut、滑鼠點選、ajax請求等時,會將對應任務新增到事件執行緒中,等待JS引擎處理
定時觸發器執行緒:
setInterval和setTimeOut所在的執行緒,計時完畢後新增到事件佇列中,
setInterval精確地隔一段時間推入一個事件(但是,事件的實際執行時間不一定就準確,還有可能是這個事件還沒執行完畢,下一個事件就來了)
多個setInterval的程式碼執行時間可能會比預期小(因為程式碼執行需要時間)
目前最佳方案是由setTimeOut模擬setInterval,或者直接用requestAnimationFrame
非同步http請求執行緒:
在XMLHttpRequest在連線後通過瀏覽器新開一個執行緒請求
檢測到狀態變更時,如果設定有回撥函式,非同步執行緒就產生狀態變更事件,將這個回撥放入事件佇列中,等待JS引擎執行緒執行
Browser程序和瀏覽器核心(Renderer程序)的通訊過程
Browser程序收到使用者請求--獲取頁面內容--通過Renderer介面傳遞給Render程序
Renderer程序的Renderer介面收到訊息--解釋--交給渲染執行緒--開始渲染
渲染執行緒接收請求--載入並渲染網頁(可能需要Browser程序獲取資源和需要GPU程序幫助渲染)
JS執行緒操作DOM(迴流、重繪)
Render程序將結果傳遞給Browser程序
Browser程序接收結果並繪製
瀏覽器核心中執行緒之間的關係
GUI渲染執行緒與JS引擎執行緒互斥
當JS引擎執行時GUI執行緒會被掛起,GUI更新則會被儲存在一個佇列中等到JS引擎執行緒空閒時立即被執行
JS阻塞頁面載入
儘量避免JS執行時間過長,否則頁面渲染會不連貫,會有頁面渲染載入阻塞的感覺。
WebWorker(屬於render程序下的一個執行緒)
針對cpu密集型計算,建立Worker時,JS引擎向瀏覽器申請開一個子執行緒(子執行緒是瀏覽器開的,完全受主線控制,而且不能操作DOM)
JS引擎執行緒與worker執行緒間通過特定的方式通訊(postMessage API,需要通過序列化物件來與執行緒互動特定的資料)
ps:
把物件轉換為位元組序列的過程稱為物件的序列化
把位元組序列恢復為物件的過程稱為物件的反序列化。
1) 把物件的位元組序列永久地儲存到硬碟上,通常存放在一個檔案中;
2) 在網路上傳送物件的位元組序列。
在很多應用中,需要對某些物件進行序列化,讓它們離開記憶體空間,入住物理硬碟,以便長期儲存。比如最常見的是Web伺服器中的Session物件,當有 10萬用戶併發訪問,就有可能出現10萬個Session物件,記憶體可能吃不消,於是Web容器就會把一些seesion先序列化到硬碟中,等要用了,再把儲存在硬碟中的物件還原到記憶體中。
當兩個程序在進行遠端通訊時,彼此可以傳送各種型別的資料。無論是何種型別的資料,都會以二進位制序列的形式在網路上傳送。傳送方需要把這個Java物件轉換為位元組序列,才能在網路上傳送;接收方則需要把位元組序列再恢復為Java物件。
SharedWorker(由獨立的程序管理)
瀏覽器所所有頁面共享,被多個Render程序共享
Chrome瀏覽器為SharedWorker單獨建立一個程序來執行JavaScript程式,在瀏覽器中每個相同的JavaScript只存在一個SharedWorker程序,不管它被建立多少次。
瀏覽器渲染流程
瀏覽器輸入url,瀏覽器主程序(Browser程序)接管,開一個下載執行緒,然後進行http請求
瀏覽器渲染流程
- 解析html建立dom樹
- 解析css構建render樹(將css程式碼解析成樹形的資料結構,然後結合DOM合併成render樹)
- 佈局render樹(Layout/reflow),負責各元素尺寸、位置的計算
- 繪製render樹(paint),繪製頁面畫素資訊
- 瀏覽器會將各層的資訊傳送給GPU,GPU會將各層合成,顯示在螢幕上。
渲染完畢--load事件--JS邏輯處理
WebKit主流程:
Moziolla的Gecko呈現引擎主流程:
load事件與DOMContentLoaded事件的先後
DOMContentLoad觸發時:僅當DOM載入完成,不包括樣式表,圖片。$(document).ready(function() { // ...程式碼... });
onload事件觸發時:頁面上所有的DOM,樣式表,指令碼,圖片都已經載入完成。$(document).load(function() { // ...程式碼... });
CSS載入
css由單獨的下載執行緒非同步下載
css載入不會阻塞DOM樹解析,但會阻塞render樹渲染(渲染時需等css載入完畢,因為render樹需要css資訊)