奇舞-關鍵渲染路徑效能優化-筆記
內容
- 瀏覽器渲染原理
- 資源對渲染的影響
- 優化關鍵渲染路徑
瀏覽器渲染原理
DOM
Timeline
錄製時需注意
- 禁用快取,以便測試首次瀏覽效能
- 關閉Chrome 擴充套件 或使用隱身模式
模式真實網路情況
Chrome Canary
總結TImeline
1:控制條
- 開始記錄, 停止記錄
- 配置記錄期間捕獲的資訊
2: 總攬
- 頁面效能高階彙總
3:火焰圖
- CPU 堆疊追蹤的視覺化
4:詳情
- 每個CPU 任務的詳細報告
增量構建
瀏覽器無需等待html 載入完畢,便可開始解析DOM
自己動手
使用 performance 工具 分析自己常逛的網站。找到主執行緒中構建DOM所在的步驟
總結
描述瀏覽器是如何構建DOM的
CSSOM
RenderTree
- RenderTree 包含了渲染網頁所需要的節點
- 無需渲染的節點不會被新增到RenderTree中。
思考Lvisitilty:hidden 的節點,是否會被新增到RenderTree?
Recalculate Style : 構建 RenderTree
Layout :計算渲染書節點的位置和大小
Viewport
- device-width 為瀏覽器的理想視口
- 在移動端 ,如果不設定viewpost 寬度為理想視口,viewport寬度通常為,980px,這會導致文字很小,我們需要手動放大閱讀
思考 :
哪些操作會觸發Layout
總結
試著畫出瀏覽器渲染過程
並描述每一步執行的工作
構建DOM
- 構建過程
character token node DOM - 增量構建
構建CSSOM
- 構建過程
charactor token node CSSOM - 選擇器越複雜,匹配用的時間越多
構建RenderTree
- RenderTree 包含所有需要呈現在頁面上的節點資訊
- display:none 的元素不會被新增到RenderTree 彙總,因為不需要本渲染
- visibility:hidden 的元素會被新增到RenderTree中,因為它雖然不可見,但是會佔有位子
Layout
- 計算需要渲染的節點的大小和位置
- 節點位置和大小是給予viewport計算的
- 在移動端通常將viewport設為瀏覽器推薦的理想適口,以保證字型顯示大小易於閱讀
- 旋轉螢幕,修改瀏覽器大小,修改位置大小相關的css屬性都有可能觸發Layout
Paint
- 根基background,border, box-shadow等樣式,將Layout生成區域填充為最終將顯示在螢幕上的畫素
資源對渲染的影響
資源
- css
- js
- font
- img
思考
瀏覽器會在何時渲染頁面
- 載入完DOM立即開始渲染
- 載入完DOM和CSSOM
css阻塞初次渲染(有待測試)
‘index.css’>
- 通過以上兩種方式定義css,均會阻塞初次渲染
- 瀏覽器會在解析完css後,再進行渲染,這是為了防止樣式突變帶來餓抖動
- 不管css 出現文件中的那個位置,都會阻塞整個文件的初次渲染
- 通過link 標籤引入的css阻塞的時間可能更長,因為載入它需要一個網路來回時間
dedia query
<link rel='sty;esheet' href='index_print.css' media='print'>
- 此樣式表仍會載入
- 當瀏覽器環境不匹配媒體查詢時,改樣式表不會阻塞渲染
- 我們可針對不同媒體環境拆分css檔案,併為link標籤新增媒體查詢,避免為了載入非關鍵css資源,而阻塞初次渲染。
通過documnt.write 新增link
<script>
document.write('<link ref='stylesheet' href='inex.css' />')
</script>
通過DOM API 新增link
var style = document.createElement(‘link’)
style.rel = ‘stylesheet’;
style.href = ‘index.css’;
document.head.appendChild(style)
不會阻塞初次渲染
preload
<link / rel='preloa' href='index_print.css' as=style onloa='this.rel=stylesheet'>
- fel 不是stylesheet,因此不會阻塞渲染
- preloa 是resoure hint 規範中定義中一個功能
- resource hint 通過告知瀏覽器提前 建立連結或載入資源,以提高資源載入的速度
- 瀏覽器遇到標記為preloa的link 時,會開始載入它
- 當onload 時間發生時,將rel改為stylesheet 即可應用此樣式
loadCSS.js
- CSS preload polyfill
- 讓我們可以使用preloa 語法非同步載入css
- 原理是通過DOM API 插入樣式資源
思考
<body>
<p>hello</p>
// 這個指令碼會載入10秒左右
<script src='slowscript.js'></script>
<p>world</p>
</body>
//顯示情況是 立即顯示hello 10秒後顯示world
javascript 阻塞HTML parser
// inline js
<script></script>
// external js
<script src='somescript'></script>
- 通過以上兩種方式引入js指令碼均會阻塞html parser,因而會阻塞出現在指令碼後面的HTML 標記的渲染
- 外部script 阻塞時間一般更長,以為可能包含了一個網路來回時間
- javascript 可以通過document.write 修改HTML 文件流,因此在執行js時, 瀏覽器會暫停解析DOM的工作
<html>
<head>
//p {color: green}
<link rel='stylesheet' href = 'index.css'>
</head>
<body>
<p>hello wrold</p>
<script>
let p = document.querySelector('p');
let color = window.getComputedStyle(p).color
console.log(color)
</script>
</body>
</html>
//如果HTML Parse 解析到<script></script> 標籤時,樣式仍未載入完成,會發生什麼? 最後列印的顏色是多少?
CSS阻塞JS
//inline js
<script> //app logics here <script>
//external js
<script src='somescript.js'></script>
- 通過以上兩種方式引入的JS均會被CSS 阻塞
- 由於這些javascript 可能會讀取或修改CSSOM,因此需要等待CSSOM 構造完成後,它們才會執行
<html>
<head>
<script src='index.js'></script>
<script> src='tongji.js' </script>
</head>
<body>
</body>
</html>
//這兩個js檔案瀏覽器會同時載入
Preloa
- 當HTML parse 被指令碼阻塞時,Parser 雖然停止構建DOM,但仍會識別該指令碼後面的資源,並提前載入。
- 注意:這裡是指的瀏覽器資源載入策略,而非前文提到的resource hint 標準中的preload
使用defer延遲指令碼執行
<script src=='index.css' defer><script>
- 當script 標籤擁有defer 屬性時,該指令碼會被退到整個HTML文件解析完成後,再開始執行。
- 被defer 指令碼, 在執行時會嚴格按照HTML文件中出現的順序位置
延遲指令碼方法對比
使用的的方法,可提早指令碼資源載入
由於HTML Parser 是增量解析 HTML文件的,因此將指令碼放在head中,可以提早瀏覽器對指令碼檔案的載入。
使用async 非同步載入指令碼
- 當script 標籤擁有async 屬性時,該指令碼不會再阻塞html parser 且不會被css 阻塞
- 指令碼只要載入完成,便可開始執行
- 被async 的指令碼,在執行時會 不會按照在html文件中出現的順序文件執行
- async 適用於無依賴的獨立資源
<link href='https://fints.googleapis.com/css...'>
<style type='text/css' media='screen. print'>
h1 {
font-family:'Roboto'
}
//載入完HTML 文件後, 瀏覽器會如何工作?
// 等字型檔案載入完成後顯示內容
</style>
font 阻塞內容渲染
- 瀏覽器為了避免FOUT(Flash Of Unstyled Text) 會盡量等字型載入完成後, 再顯示應用了該字型的內容
- 只有當字型超過一段時間仍未載入成功時, 瀏覽器才會降級使用系統字型,每個瀏覽器都規定了自己的超時時間
- 但這也帶來了FOIT(falst Of invisible Text) 問題, 內容無法儘快被展示,導致空白。
非同步載入字型
通過非同步載入css 。即可避免字型阻塞渲染
<body>
<img src='smile.png'>
<p>hello world</p>
</body>
//圖片資源是否會阻塞首次渲染 答案是不會
優化關鍵渲染路徑
優化目標
將一下指標壓縮到最低
- 關鍵資源數
- 關鍵資源體積
- 關鍵資源網路來回數
勿盲目內聯資源
- 若啟用HTTP2 ,則無需內聯資源
- 若資源被多個頁面共享,則無法充分利用快取, 導致重複下載
結合內聯與快取
<html>
<head>
<style></style>
<link rel='prefetch' href = 'index.css'></link>
</head>
<body>
<p> hello world</p>
</body>
</html>
- 當用戶首次訪問時,返回內聯資源,並通過prefetch,請求並快取資源;
- 在使用者首次訪問時, 通過cookie 表示使用者已載入快取
- 當下次訪問時, 若cookie 標示已經快取過,則只返回外部資源標記
- 快取策略可靈活選擇
減少內容大小
- 避免返回無用內容
- 針對特定語言的原始碼壓縮
- 通過文字壓縮
- 圖片壓縮
關鍵呈現路徑優化思路
- 延遲或非同步載入資源, 從而減少關鍵資源數量
- 減少資源大小
- 針對關鍵資源, 減少網路請求時間
學習資源
- 關鍵資源呈現路徑, by Chrome Developer
- 使用Chrome Devtool 檢查效能
- 效能優化相關資源彙總