一路上感謝各位讀者們的支持和回饋。
本 30 天系列文目前已經將篇幅重新整理、編纂成冊。
《JavaScript 概念三明治》在天瓏書局上架囉!
喜歡這個系列,想閱讀更詳細原理說明的讀者可以參考:
https://www.tenlong.com.tw/products/9789864347575
當使用者進入頁面、瀏覽器收到請求並回傳前端相關檔案後,到最後使用者看到的畫面呈現之前,還有很多步驟會被執行,這一連串步驟的總和就稱為 Critical Rendering Path ( 中譯:關鍵渲染路徑),了解關鍵渲染路徑,在網站前端頁面需要做效能優化時,就可以比較容易知道,要從哪裡下手。
關鍵渲染路徑(以下簡稱 CRP ) 大致上會執行以下六個步驟:
下面就讓我們一個步驟一個步驟詳細來看:
前一章節有講到網頁的 DOM 是根據 HTML 內容而來,這個轉換的過程有點像這個系列一開頭我們討論 JS 語法解析那段,瀏覽器會根據 HTML Tag 將內容轉為一個一個 Token (標記)
之後會根據這些 Token 將對應的標籤轉換成節點,之後根據 Token 的前後關係產生出 DOM Tree 。
CSSOM ( CSS Object Model ) 是代表跟 DOM 元素對應樣式的物件。他的表現形式跟 DOM 很像,只是 CSSOM 是依附著每個節點,各個節點都會有對應的樣式 ( Style ),所以基本上 CSSOM Tree 跟 DOM Tree 長的會很像。
這邊要注意的是,CSS 在頁面載入行為裡,是屬於鎖定渲染的資源( Render Blocking Resource ),意思是,在頁面仔入時,只要還沒有拿到所有的 CSS 檔案並成功載入,那瀏覽器就會等到完成載入為止,這意味著,每個網頁上的 CSS 檔案,都會拖到載入速度。
除了 Render Blocking ,也有人說 CSS 是 「Script Blocking 」,因為在瀏覽器載入所有的 CSS 檔案之後,瀏覽器才會進入的我們的下一步「執行 JS」。 在產生 CSSOM 時,越多層的選擇器,在元素與樣式的匹配上會需要更多時間來進行。以下面這兩個 CSS 類別為例:
A : p { color:red; }
B : div h1 { font-size:22px;}
第二種 B 情況的 CSS 會需要更多時間來做匹配,首先瀏覽器會先找到頁面上所有的 h1
元素,而後在看這個元素的父類別是不是一個 div
元素 ,因此瀏覽器在匹配樣式時其實是以「從右邊到左邊」的順序來進行的,所以現在你就了解,如果你有加速前端渲染速度的請求,就要減少 CSS 選擇器層級的長度,在這方面,BEM 的 CSS 命名撰寫風格就把層級關係透過命名的方式來表達,同時也大幅度的減少選擇器的少用次數,建議對 CSS 有興趣鑽研的人一定要看一下。
類似的命名風格或規範,除了 BEM 之外還有 OOCSS 跟 SMACSS ,這些規範都是透過一些原則,來達到最大程度的減少重複,除了好維護之外,其實也能提升畫面渲染的效率,這也是為什麼這些規範常常被資深前端人員提起、並視為圭臬的原因。
JS 則是鎖定轉譯,在 JS 執行完之前,瀏覽器都不會繼續做 HTML 文件的轉譯跟建構。當瀏覽器轉譯時碰到 <script>
,他會停下來等到 JS 執行完成之後才會再往下。這也是為什麼我們常常說要把 <script>
標籤放到整個網頁最後面的原因。
渲染樹 (Rendering Tree) 其實就是 DOM 搭配 CSSOM 的結果,在用白話一點的方式來說,就是「最後會被渲染在畫面上」的結構樹,所以如果 CSS 樣式導致某個 Node 沒辦法顯示,( 如display:none
),那麼他就不會出現在渲染樹上。
我們已經取得代表元素層級關係的 DOM 樹結構,也匹配了個元素對應的樣式,最終搭配兩者產生出了渲染樹,現在我們離最後產生可視畫面的階段已經不遠了,但是還差一個步驟,我們還必須弄清楚所有元素的實際位置,以及元素該如何呈現,那就是產生畫面編排 ( Layout ) 的步驟。
Layout 產生的方式,會跟 meta tag
裡面的 viewpoint 屬性有很大的關係:
<meta name="viewport" content="width=device-width, initial-scale=1.0">
viewpoint
的 meta
tag 用來告訴瀏覽器,頁面要怎麼縮放,還有維度,就是指畫面像素(瀏覽器畫面)跟螢幕像素(硬體)的比例,content
之中,width
用來設定瀏覽器畫面寬度是多少,把他設定成 device-width
的話就是在告訴瀏覽器,畫面顯示的螢幕寬度要跟硬體裝置相同(手機、電腦),如果沒給 width
值的話,瀏覽器就會使用預設的 980px
來當作預設的畫面顯示寬度。這個屬性在 HTML5 後出現,常用在 RWD 的設計實作之中。 initial-scale=1.0
是指預設的縮放程度,最常見的值也是預設值,就是 1
。
到最後一個步驟,瀏覽器進入到了繪製階段,前面提到一連串很抽象的設定跟結構,終於可以被轉換成一個個像素,繪製階段所花的時間會跟 DOM 結構樹 與 CSSOM 樹的大小、規模有關,越複雜的結構或是樣式就會需要更多時間,應該不難理解。
我們透過瀏覽器的檢查工具,也能看出上面講的 CRP 六個步驟,是不是真的依照順序進行,以 Chrome 為例子,打開開發者工具,並切換到 Performance 之後,按下錄影,重新整理之後結束錄影,就能夠看到這段時間內瀏覽器是怎麼產生畫面的:
對應前面步驟說明:
1、2: 拉取資源並解析 DOM 樹
為 index.css 解析 CSSOM 樹
執行 JavaScript 檔案 ( index.js )
根據 viewpoint 的 meta tag 產生layout
繪製螢幕
Google 在 Udacity 的教學真的講的蠻仔細的,搭配圖文也能更讓學習者一目瞭然: