Life of a Pixel 演講的學習筆記。瀏覽器的渲染過程極爲的複雜,演講的語速也特別的快,因此若有錯誤請及時指出。css
前端的全部代碼統稱爲Content,好比html,js,css,圖片,視頻等。html
在Chromium代碼架構上Content命名空間包含了,黃色框內的全部內容。在Chromium代碼中由WebContent類表示,WebContent類中封裝了渲染進程。前端
Chromium是Google的開源項目,Chrome瀏覽器就是基於Chromium代碼實現,Edge,Opera也是基於Chromium代碼。git
Blink是瀏覽器排版引擎,屬於Chromium中的一部分。Blink屬於Content中渲染過程代碼的子集。github
總結一下:在Chromium中WebContent類負責Content的渲染,渲染過程交由Blink實現web
parsing(解析HTML)-> style (生成樣式規則模型) -> layout(生成佈局對象)-> compositing update (輸入合成)-> paint(繪製)-> commit(提交)-> tiling(切割)-> raster(柵格化)-> draw quads -> display(顯示到屏幕上)瀏覽器
瀏覽器並不能只靠本身將網頁渲染到屏幕上,瀏覽器的渲染須要使用底層操做系統提供的圖形庫,好比OpenGL API。可是OpenGL並不認識Html,Css這些內容,因此須要經過瀏覽器的Web Content須要將Html,Css轉換成OpenGL能夠識別的內容,而後經過OpenGL渲染到屏幕上。緩存
在渲染到屏幕以後,須要監聽並響應,JavaScript,用戶輸入,異步加載,動畫,滾動,縮放,而後進行渲染更新。對於一些更新渲染,是不須要從頭走徹底部的渲染流程的。網絡
從網絡請求開始,最早獲取的是html文件,因此瀏覽器渲染的起點,是HTML解析器。同時HTML中引入了CSS,JS,圖片等資源,瀏覽器也會加載它們。架構
HTML文件的解析過程:
HTML文件 -stream-> HTMLDocumentParser(HTML文檔解析器)-> HTMLTreeBuilder(HTML樹構建器)-> DOM
DOM是基於HTML的倒着的樹形結構,DOM有兩個做用:
CSS樣式表的解析過程:
CSS樣式表 -> CSSParser(CSS解析器)-> 樣式規則模型(Style Rule Model)
CSS樣式是如何做用與DOM的?
根據已經解析的樣式規則(Style Rule),和瀏覽器的默認樣式,計算出每個DOM的樣式。樣式和屬性值存儲在一個巨大的ComputedStyle對象中。ComputedStyle對象是屬性和屬性值的映射。ComputedStyle對象中會掛載元素,應對應不一樣元素的不一樣樣式。
在構建完DOM並完成樣式計算後,須要肯定全部元素的幾何形狀(幾何形狀所佔的區域以及座標),這些佈局信息稱爲LayoutObject對象,
佈局對象(LayoutObject)保存佈局樹中,並與DOM關聯。不一樣的節點,對應不一樣的佈局類。可是不一樣佈局類都繼承自LayoutObject這個父類。
LayoutObject對象和DOM元素並非一一對應的。好比當DOM元素的樣式是display: none
時,是沒有LayoutObject對象的。
輸入合成階段,咱們在下面講🍵
根據佈局對象(LayoutObject),繪製操做會將繪製操做記錄在一個待顯示項目列表(display items list)中。
什麼是繪製操做?好比,根據佈局對象(LayoutObject)在指定區域繪製一個紅色的矩形。這就是繪製操做。
每個佈局對象(LayoutObject)對應多個待顯示項目,由於可能涉及到繪製不一樣的部分。目前只是記錄繪製操做,還沒有執行繪製操做。繪製的順序,受控於z-index
屬性。
提交,分割階段,咱們在下面講🍵
待顯示項目列表中繪製的實際操做,是由柵格化進程執行的。
柵格化會將待顯示項,轉換爲顏色值的位圖(將圖像的信息,以像素爲單位記錄,記錄每個像素點的顏色信息rgba值)。位圖信息保存在內存中(一般是顯存中)。gpu也能夠將待顯示項目列表柵格化,咱們稱爲gpu加速。此時位圖信息還保存在顯存中,沒有輸出到屏幕上。
對於圖像信息,柵格化會對圖像進行解碼,獲取位圖信息。
柵格化的過程是經過SKIA庫調用OpenGL API完成的。
SKIA是一個開源的圖形引擎,SKIA能夠實現柵格化,PDF輸出,GPU加速。
draw quads階段,咱們在下面講🍵
SKIA產生OpenGL調用,使用命令緩存區的形式,傳輸到GPU進程,GPU接受到命令緩存,產生GL調用。像素被渲染到屏幕上了。
commit(提交)-> tiling(切割)-> raster(柵格化)-> draw quads -> display(顯示到屏幕上)
渲染不是靜態的,JavaScript,用戶輸入,異步加載,動畫,滾動,縮放,都會改變渲染。從頭執行渲染流程代價會很昂貴。若是每一秒低於60fps,就會變得卡頓。
爲了不從頭執行整個渲染流程,經常使用的優化方法就是標記出,發生了改變的部分,複用沒有改變的部分。好比一個節點須要從新計算樣式,在下一幀的時候,只從新計算該節點的樣式。
Chrome另外的優化手段是分層
動畫,滾動,縮放,操做都會建立圖層。單獨的合成線程,會對滾動輸入操做,進行單獨處理。
while(true) {
}
複製代碼
當咱們使用js阻塞主線程時,因爲單獨的合成線程的存在,合成線程會對用戶的滾動操做進行處理,雖然主線程被阻塞可是頁面依然能夠滾動
圖層的存儲結構也是樹的形式,圖層樹間接的基於佈局樹。
compositing update(輸入合成)階段發生在Layout(佈局)階段以後,Paint(繪製)階段以前。對頁面進行分層,每一個圖層被分別繪製。繪製階段存在的待顯示項目列表(display items list),其實不一樣的圖層擁有不一樣的待顯示項目列表(display items list)
繪製完成後,經過同步主線程的狀態,更新合成線程圖層的狀態,最後同步回主線程
Raster會將待顯示項目列表(display items list)轉換爲位圖,可是有時候圖層會很大,Raster又是一個開銷很大的步驟,合成線程會將圖層分割爲圖塊,圖塊是Raster的基本單位。距離視口越近,會優先建立圖塊優先被柵格化。
圖塊會在單獨Raster線程中柵格化
在繪製完全部圖塊以後,合成器線程將生成draw quads
,draw quads
是繪製圖塊的指令,draw quads
被包裝在合成器框架對象中,提交給瀏覽器進程。
瀏覽器進程,運行顯示合成器的組件,合成器組件調用OpenGL繪製draw quads
,最後像素在用戶的屏幕上可見。