轉譯器程序的內部工作
這是探討瀏覽器運作方式的網誌系列文章 (共 4 集),此為系列文章第 3 部分。我們先前已介紹過多程序架構和導覽流程。在本文中,我們將說明轉譯器程序內部發生的情況。
轉譯器程序涵蓋網頁效能的許多層面,由於轉譯器程序中進行了許多活動,因此本文只是一般總覽說明。如要深入瞭解相關資訊,請前往 Web Fundamentals 的「效能」部分瞭解詳情。
轉譯器程序會處理網頁內容
轉譯器程序會負責分頁內發生的所有內容。在轉譯器程序中,主執行緒會處理您傳送給使用者的大部分程式碼。如果您使用網路工作站或服務工作站,有時 JavaScript 的某些部分會由工作站執行緒處理。也會在轉譯器程序中執行合成器和光柵執行緒,以有效率且順暢的方式轉譯頁面。
轉譯器程序的核心工作是將 HTML、CSS 和 JavaScript 轉換成使用者可互動的網頁。
![轉譯器程序](https://developer.chrome.com/static/blog/inside-browser-part3/image/renderer-process-df424472d0633.png?authuser=19&hl=zh-tw)
剖析
DOM 建構
當轉譯器程序收到導覽的修訂訊息並開始接收 HTML 資料時,主執行緒會開始剖析文字字串 (HTML),並將其轉換成 Document Object Model (DOM)。
DOM 是瀏覽器的內部表示法,以及網頁程式開發人員可透過 JavaScript 互動的資料結構和 API。
將 HTML 文件剖析為 DOM 是由 HTML 標準定義。您可能已經注意到,傳回 HTML 給瀏覽器時不會擲回錯誤。例如,缺少 </p>
結尾標記是有效的 HTML。系統會將 Hi! <b>I'm <i>Chrome</b>!</i>
等錯誤標記 (b 標記在 i 標記之前關閉) 視為您編寫 Hi! <b>I'm <i>Chrome</i></b><i>!</i>
。這是因為 HTML 規格的設計目的是妥善處理這些錯誤。如果您想瞭解實際執行方式,請參閱 HTML 規格的「簡介錯誤處理和剖析器中的奇怪案例」一節。
正在載入子資源
網站通常會使用圖片、CSS 和 JavaScript 等外部資源。您需要從網路或快取載入這些檔案。主要執行緒「可」在剖析建構 DOM 時找到它們,逐一提出要求,但為了加快速度,系統會同時執行「預先載入掃描器」。如果 HTML 文件中含有 <img>
或 <link>
等項目,預先載入掃描器會預覽 HTML 剖析器產生的權杖,並在瀏覽器程序將要求傳送至網路執行緒。
![DOM](https://developer.chrome.com/static/blog/inside-browser-part3/image/dom-ffeed8e96a6e8.png?authuser=19&hl=zh-tw)
JavaScript 可以阻擋剖析
當 HTML 剖析器找到 <script>
標記時,會暫停剖析 HTML 文件,而且必須載入、剖析及執行 JavaScript 程式碼。因為 JavaScript 可以用類似「document.write()
」來變更整個 DOM 結構 (剖析模型總覽HTML 規格中的一個很好的圖表) 來變更文件的形狀。因此,HTML 剖析器必須等到 JavaScript 執行完畢之後,才能繼續剖析 HTML 文件。如果您想知道 JavaScript 執行會發生的情況,V8 團隊可以進行相關討論和網誌文章。
向瀏覽器顯示如何載入資源的提示
網頁程式開發人員可透過多種方式將提示傳送給瀏覽器,以便順利載入資源。
如果 JavaScript 不使用 document.write()
,您可以在 <script>
標記中加入 async
或 defer
屬性。接著,瀏覽器會以非同步方式載入並執行 JavaScript 程式碼,不會封鎖剖析作業。如果適用,您也可以使用 JavaScript 模組。<link rel="preload">
能夠告知瀏覽器目前的瀏覽中絕對需要該資源,而您想要盡快下載。詳情請參閱「資源優先化 - 讓瀏覽器助您一臂之力」。
樣式計算
因為我們能在 CSS 中設定網頁元素樣式,所以使用 DOM 不足以瞭解網頁的外觀。主執行緒會剖析 CSS,並決定每個 DOM 節點的計算樣式。這會說明根據 CSS 選取器為每個元素套用的樣式類型。您可以在開發人員工具的 computed
部分查看這項資訊。
![運算樣式](https://developer.chrome.com/static/blog/inside-browser-part3/image/computed-style-5e3c65a01f3f1.png?authuser=19&hl=zh-tw)
即使您未提供任何 CSS,每個 DOM 節點都會有計算樣式。<h1>
標記顯示的大小比 <h2>
標記更大,而且邊界的邊界是為每個元素定義的。這是因為瀏覽器有預設的樣式表。如要瞭解 Chrome 的預設 CSS,請參閱這裡的原始碼。
版面配置
現在,轉譯器程序知道每個節點的文件結構和樣式,但是在轉譯頁面還不夠。假設您要透過手機向朋友描述畫作。「紅色大圓圈與小型藍色正方形」資訊不足,無法讓好友知道這幅畫的實際樣貌。
![人類傳真機遊戲](https://developer.chrome.com/static/blog/inside-browser-part3/image/game-human-fax-machine-17f10d8b400ac.png?authuser=19&hl=zh-tw)
版面配置是找出元素幾何圖形的程序。主執行緒會逐步介紹 DOM 並計算樣式,並建立版面配置樹狀結構,其中包含 x y 座標和定界框大小等資訊。版面配置樹狀結構雖然與 DOM 樹狀結構類似,但只包含與頁面上顯示內容相關的資訊。如果套用 display: none
,該元素就不會包含在版面配置樹狀結構中 (然而,具有 visibility: hidden
的元素位於版面配置樹狀結構中)。同樣地,如果套用 p::before{content:"Hi!"}
等內容的虛擬元素,即使該元素不在 DOM 中,也會納入版面配置樹狀結構中。
![版面配置](https://developer.chrome.com/static/blog/inside-browser-part3/image/layout-9d8ed8c743f45.png?authuser=19&hl=zh-tw)
判斷網頁的版面配置並不容易。即使是最簡單的頁面版面配置 (例如從上到下區塊流程),也需要考量字型的大小和分隔位置,因為這會影響段落的大小和形狀,而這會影響以下段落的所需位置。
CSS 可以將元素浮動到其中一側、遮蓋溢位項目,以及變更寫入方向。想像一下,這個版面配置階段要處理一個很厲害的工作。在 Chrome 中,整個工程師團隊會處理這個版面配置。如果您想查看他們的作品詳細資料,我們會錄製幾場 BlinkOn Conference 的演講,並歡迎您立即觀看。
塗料
![繪畫遊戲](https://developer.chrome.com/static/blog/inside-browser-part3/image/drawing-game-7902ad8a91d2f.png?authuser=19&hl=zh-tw)
包含 DOM、樣式和版面配置仍不足以轉譯網頁。假設您要重現一幅畫作您知道元素的大小、形狀和位置,但仍需決定元素的繪製順序。
舉例來說,某些元素可能會針對 z-index
設定,這樣系統就會按照在 HTML 中編寫的元素順序繪製順序,導致算繪錯誤。
![Z-index 失敗](https://developer.chrome.com/static/blog/inside-browser-part3/image/z-index-fail-2529cf989dc65.png?authuser=19&hl=zh-tw)
在這個繪製步驟中,主執行緒會引導版面配置樹狀結構建立繪製記錄。繪製記錄是「先從背景、文字再到矩形」等繪製程序的附註。如果您已使用 JavaScript 在 <canvas>
元素上繪圖,那麼您可能很熟悉這項程序。
![油漆記錄](https://developer.chrome.com/static/blog/inside-browser-part3/image/paint-records-151165f18a91e.png?authuser=19&hl=zh-tw)
更新轉譯管道所費不貲
關於轉譯管道,最重要的重點是,在先前作業的每個步驟結果中,都會用來建立新資料。舉例來說,如果版面配置樹狀結構中有異動,就必須為受影響的文件部分重新產生套用順序。
如果要為元素建立動畫效果,瀏覽器必須在每個頁框之間執行這些作業。我們大部分的螢幕每秒都會重新整理畫面 (每秒 60 個影格)。當您在每個影格中移動項目時,動畫就會呈現平滑的視覺效果。不過,如果動畫沒有移除影格中的影格,頁面就會顯示「卡頓」。
![因缺少影格而發生 jage 資源浪費](https://developer.chrome.com/static/blog/inside-browser-part3/image/jage-jank-missing-frames-187496b8fbc8e.png?authuser=19&hl=zh-tw)
即使您的轉譯作業會跟螢幕重新整理一樣,這些計算都在主執行緒上執行,所以在應用程式執行 JavaScript 時,可能會遭到封鎖。
![JavaScript 的 jage jank](https://developer.chrome.com/static/blog/inside-browser-part3/image/jage-jank-javascript-b19c0193934a3.png?authuser=19&hl=zh-tw)
您可以將 JavaScript 作業分成多個小區塊,並利用 requestAnimationFrame()
安排在每個影格中執行。如要進一步瞭解這個主題,請參閱「最佳化 JavaScript 執行作業」。也可以在網路工作站中執行 JavaScript,避免封鎖主執行緒。
![要求動畫影格](https://developer.chrome.com/static/blog/inside-browser-part3/image/request-animation-frame-3b04e26660019.png?authuser=19&hl=zh-tw)
合成中
如何繪製頁面?
現在瀏覽器已經知道文件的結構、每個元素的樣式、網頁的幾何圖形和繪製順序,那麼瀏覽器該如何繪製頁面?將這些資訊轉換成螢幕上的像素 稱為光柵化
處理這種情況最簡單的方式,是在可視區域內的光柵部分。如果使用者捲動網頁,然後移動光柵頁框,再按光柵來填滿缺少的部分。這是 Chrome 首次發布光柵化時的處理方式。不過,新式瀏覽器會執行更複雜的程序,稱為合成。
什麼是組成
合成是一項技術,可將網頁的某些部分分拆成不同圖層、分別將各部分光柵化,並在另一個稱為合成器執行緒的獨立執行緒中合併成一個頁面。如果捲動發生,由於圖層已經光柵化,您只需合併新的影格即可。動畫可透過移動圖層及合併新影格的方式達成。
您可以使用「Layers」面板,在開發人員工具中瞭解網站如何分割成不同圖層。
分割為多個圖層
為了找出元素需要位於哪個圖層,主執行緒會逐步完成版面配置樹狀結構,建立圖層樹狀結構 (這個部分在開發人員工具效能面板中稱為「更新層樹狀結構」)。如果頁面上應該獨立圖層 (例如滑入式選單) 的某些部分沒有出現,您可以在 CSS 中使用 will-change
屬性向瀏覽器提示。
![多層樹狀結構](https://developer.chrome.com/static/blog/inside-browser-part3/image/layer-tree-cc92336966c73.png?authuser=19&hl=zh-tw)
您可能想要為每個元素提供圖層,但若融合多餘的圖層,可能會導致運作速度變慢,而不是每個影格只光柵化頁面的微小部分,因此請務必評估應用程式的轉譯效能。如要進一步瞭解相關主題,請參閱「Stick to Compositor-Only Properties and Manage Layer Count」一文。
來自主執行緒的光柵和複合資料
建立圖層樹狀結構並確定繪製順序後,主執行緒會將該資訊提交至合成器執行緒。接著,合成器執行緒會點光每個圖層。圖層可以很大,就像整個頁面的長度一樣,因此合成器執行緒會將其分割成資訊方塊,並將每個圖塊傳送至光柵執行緒。光柵執行緒會光柵執行緒擷取每個資訊方塊,並將其儲存在 GPU 記憶體中。
![光柵](https://developer.chrome.com/static/blog/inside-browser-part3/image/raster-9dfd7af5a9554.png?authuser=19&hl=zh-tw)
合成器執行緒可以優先處理不同的光柵執行緒,以便先對可視區域 (或鄰近) 中的項目進行光柵化。此外,圖層也有不同解析度的多種圖塊,用於處理放大動作等項目。
圖塊送出後,合成器執行緒會蒐集名為「繪製序列」的資訊方塊資訊,藉此建立合成器框架。
繪製四頭形 | 包含資訊,例如在記憶體中的圖塊位置,以及要在網頁中繪製圖塊時,會將該方塊納入考量的頁面位置。 |
合成器框架 | 一組代表頁面頁框的繪製四邊形。 |
隨後,合成器框架會透過 IPC 提交至瀏覽器程序。此時,您可以透過 UI 執行緒新增另一個合成器影格,用於瀏覽器 UI 變更,或是從其他轉譯器程序的擴充功能轉譯程序。這些合成器影格會傳送到 GPU,並在螢幕上顯示。如果有捲動事件,合成器執行緒會建立另一個合成器影格並傳送至 GPU。
![合成](https://developer.chrome.com/static/blog/inside-browser-part3/image/composit-266744978ac93.png?authuser=19&hl=zh-tw)
合成的好處是無需與主執行緒互動就能完成。因此合成器執行緒無須等待樣式計算或 JavaScript 執行作業。因此,只組合動畫是為了確保流暢效能。如果需要再次計算版面配置或繪製作業,就必須涉及主執行緒。
總結
在這篇文章中,我們探討了從剖析到合成等轉譯管道。希望您現在能閱讀更多網站效能最佳化的相關資訊
在本系列的下一篇文章中,我們將更詳細地介紹合成器執行緒,並說明 mouse move
和 click
等使用者輸入內容進入後會發生什麼情況。
你喜歡這則貼文嗎?如果您對日後貼文有任何疑問或建議,歡迎您透過下方的留言專區或在 Twitter 使用 @kosamari 聽到您的想法。