從 App 的生命週期來看瀏覽器渲染效能優化
16 Jul 2018以使用者的角度來看如何優化效能-App 的生命週期,讓開發者在 App 生命週期的各階段對於優化工作能做更好的選擇。
RAIL
RAIL 是 Google 提出以使用者為中心的效能建議,各階段要做的事和最多可花費的時間,若符合原則可讓使用者在操作時感到順暢。
圖片來源:Measure Performance with the RAIL Model
這四個英文字母代表的意義分別是
- R:Response,收到使用者與 UI 互動後得到反應的時間,最多是 100ms。
- A:Animation,盡量符合 60fps,最多 16ms。實際上,由於瀏覽器有很多工作要做,因此大約是 10 ~ 12ms。
- I:Idle,互動結束後等待下一次與使用者互動的空擋,大約是 50ms。
- L:Load,頁面資源載入最多花 1 秒。
範例 1
舉例來說,使用者點擊按鈕後會是這樣的狀況…
圖片來源:App Lifecycles: RAIL - Animations Part 2
說明
- 使用者點擊按鈕後,期望得到回饋,這個回饋可能是開始某個動畫。從點擊到動畫開始,最多讓使用者等待 100 ms。
- 動畫從開始到結束,維持很順暢的更新頻率 60 fps。
- 動畫結束後,可能是 (1) 進入 idle 狀態待使用者下一次的互動(最多等待 50ms)或 (2) 給予另外的回饋(最多等待 100ms)。
範例 2
在 Idle 階段,處理什麼事情是適合的?
- (A) 文字顯示
- (B) 圖片下載
- (C) 影片下載
- (D) 基本或重要功能
- (F) 留言區塊
答案是 B、C、E,這階段適合載入使用者稍後會用到的 assets。基本上,當畫面載入完畢 (A) 文字顯示 和 (D) 基本或重要功能 必定已完成。
Threshold
若 Browser Rendering Pipeline 要符合 RAIL,所必須達到的門檻值。
圖片來源:Making a Silky Smooth Web
例如,若動畫必須控制在 10ms,那麼
- 樣式計算(Style Calculations)要在 1ms 以內
- 版面配置(Layout)要在 3ms 以內
- 圖層管理(Layer Management)要在 2ms 以內
- 合成(Composite)要在 2ms 以內
FLIP
FLIP 是一個方法(非框架),它可將位置和尺寸這些高成本的動畫,例如使用 width、height、position 等,轉換為使用 transform 的方式來實作,進而讓動畫能達到 60fps。原理是透過紀錄元素的初始(F)和結束(L)的兩個快照,然後對這個元素使用 transform 來做反轉(I),讓元素看起來還在初始狀態,最後移除元素上的 transform 來讓元素從初始狀態開啟播放動畫(P)到結束。
這四個英文字母代表的意義分別是
- F:First,起始,元素的起始時的位置和尺寸。
- L:Last,終止,元素的結束時的位置和尺寸。
- I:Invert,反轉,元素改變的過渡階段,依得到的反轉值從終止狀態回推倒起始狀態。
- P:Play,播放,使用 transform 並將反轉值代入,模擬元素結束狀態回推到起始狀態。
以上聽起來很抽象,但也就是經由一些數學運算,將原本使用花成本的指令來實作的動畫改用 transform 來完成。
範例
展示如何使用 FLIP 轉換高成本動畫,改以 transform 實作。
轉換前
這裡有一個藍色小方塊,它會從上方移動到下方,若用 position 的 top 來看,就是從 0 移動到 200px 處,注意外圍有 padding 15px。
點此看 Demo。
若使用 position 來實作動畫,使用 Chrome DevTools 檢視,畫面更新頻率為 3 fps。
步驟說明,也就是程式碼解析
- F(First):使用
getBoundingClientRect
取得起始位置 - L(Last):使用
getBoundingClientRect
取得結束位置 - I(Invert):取得起始與結束的差值 invert,例如:
const invert = first.top - last.top;
- P(Play):使用 transform 並將反轉值代入,模擬元素結束狀態回推到起始狀態。
轉換後
經由 FLIP 方法的計算後,invert 的值為 -185,也就是說,可使用 transform 往下移動 185px。
點此看 Demo。
使用 Chrome DevTools 檢視,畫面更新頻率為 60 fps。