1. 程式人生 > >JS執行機制(學習筆記)

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請求

瀏覽器渲染流程

  1. 解析html建立dom樹
  2. 解析css構建render樹(將css程式碼解析成樹形的資料結構,然後結合DOM合併成render樹)
  3. 佈局render樹(Layout/reflow),負責各元素尺寸、位置的計算
  4. 繪製render樹(paint),繪製頁面畫素資訊
  5. 瀏覽器會將各層的資訊傳送給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資訊)