HTML
async & defer
傳統 HTML 在解讀時,到了 <script> 便會暫停並執行 JS 直到完成後繼續解析。
為了避免這一情況發生,最簡單暴力的方式就是把 JS 連結放置在最下方。
而後來為了避免這種卡住的狀況,
HTML 4 新增了 defer 屬性
HTML 5 新增了 async 屬性
defer = true
當瀏覽器解析到 JS 連結時,defer 屬性會讓瀏覽器繼續執行同時下載所需資源,最後解析結束後才會依序執行 JS。
async = true
async 雖然跟 defer 一樣會同時下載所需資源,但不同的是 async 會在下載完成時立刻暫停 HTML 的解析,開始執行 JS ,結束後繼續 HTML 的解析。
type = "module"
主流現代瀏覽器中還能透過 type = "moudule" 來聲明此 JS 是獨立模組,這時這個 JS 的解析行為會像 defer 一樣,背景下載,等待解析完成才執行 JS 。
可以更改 async 屬性。
defer 會無法生效。
CSS
Reflow & Repaint
Reflow & Repaint 是 CSS中影響效能的兩個因素
以下的行為會觸發 Reflow
- 設定CSS屬性
大小﹑浮動﹑定位 等等...
- 使用者進行互動
調整視窗大小﹑輸入框的內容變更
- JavaScript
DOM操作﹑動態載入CSS﹑獲取元素的 Layout 相關屬性
Repaint 為渲染行為,Layout 計算完畢後,會執行 Paint 。
只要是螢幕上的實際像素產生變化便會觸發 Repaint。
瀏覽器是如何優化效能的
因為 Layout 的計算相當花費資源,所以設計者設下規則,當 Reflow 時,瀏覽器會自動批次執行。
而當 DOM 元素被觸發變化時,瀏覽器會自動根據變化省略不需要的步驟。
EX.
- width 變化 : 先 Reflow 後 Repaint
- color 變化 : 跳過 Reflow,直接進入 Repaint
常見的優化方法如下
屬性替換
- 用 translate 代替 top﹑right等定位屬性
- 表格的物理屬性會互相影響,進而觸發 Reflow,所以避免使用 table 進行排版
批次修改
使用 JS 修改 CSS 時,盡量設定為批次修改
- 替換 class name 或修改 cssText,而不是對 DOM 的 style 屬性逐條設定
- 透過 el.cloneNode() 複製一份 DOM,複製的 DOM 修改樣式後,替換原本的 DOM
- 透過 document.createDocumentFragment() 建立 Docment Fragments,編輯 DOM 後再加回 DOM tree 中
減少影響範圍
- 避免 DOM﹑CSSOM tree 的層級過深,加快 Layout 計算
- 透過 JS 取得 DOM 屬性時,先暫存起來,不要重複觸發 Reflow
- 變化頻繁的地方建立單獨的圖層( Stacking Context ),降低 Reflow 計算複雜度
z-index & Stacking Context
當 postition 屬性變動時就會產生一個新的 CSS 堆疊環境 ( Stacking Context )而堆疊環境內 CSS 樣式改變時,不會觸發其他堆疊環境的 Reflow 。
瀏覽器在渲染時,Render Tree 會在計算 Layout﹑Paint 後,
產生各個堆疊環境 ( 類似圖層 ) 而後將 堆疊環境 合成。
其中的 Layout﹑Paint 的計算會發生在各自的堆疊環境中。
z-index 也是在堆疊環境中計算的,所以 z-index 無法影響其他堆疊環境。
會建立堆疊環境的行為
- 根元素 <html></html>
- position 設置為 firxed or sticky
- postition 設置為 relative or absolute && 有設置 z-index
- 有設置 transform 屬性
- opacity < 1
另外 DevTools 中的 Layers 頁籤可以確認目前頁面的圖層
元素選取器的運作
CSSOM Tree
JS
FE
BE
WEB