[Performance]瀏覽器運作與效能指標評估

Reading time ~3 minutes

透過這次撰寫 Performance Report 的機會,學習一點瀏覽器運作的方法和網頁效能指標。

Performace 標籤總攬

這頁是我們這次的觀察範例: Yahoo 購物中心的 Mobile 版時時樂頁面。開啟 Chrome Dev Tool 的 Performance Tab 後按重新整理,會看到下圖。

Metric Image 01

Google 的 Performance tunning 教學可以參考此篇,下面會根據上圖的四個區塊再做一些解釋:

(1) Capture settings:按右上角的”齒輪”開啟設定,我們用它來設定跟環境相關的參數,像是降低 CPU 速度、模擬 3G 網速環境之類。

  • 發現網頁有渲染阻塞時,勾選 Enable “Advanced paint instrumentation (slow)”後,便可以在 Paint Profiler 看到更詳細的渲染事件過程,詳見此篇的 See Li’s answer

  • 沒有勾選 Disable JavaScript samples 時,會看到 JS call stack 的全部過程,如果你對 JS function 的呼叫過程沒興趣,可以勾選 Disable JavaScript samples,讓 Main 區塊乾淨一些。

    • 下方第一張圖是 rushbuy.js 在時時樂頁面的執行過程。由左到右是時間,由上到下是 function 呼叫順序。如圖,Rushbuy.js 執行了 window.webpackJsonp,這部分的 code 是 webpack 在打包時插入的,目的是使前端資源調用時能正常運作,稱為 webpack runtime。window.webpackJsonp 呼叫相對應的 JS 資源,該 JS 檔會再繼續呼叫此頁面使用到的 React component。
    • 下方第二張圖是勾選 Disable JavaScript samples 時的畫面,少了 JS call stack 花花綠綠的紀錄,看起來清爽許多。

Metric Image 02

Metric Image 03

(2) Overview: 第二個部分是渲染過程總覽,含三個部分,FPS、CPU 和 Net。

  1. FPS 代表每秒幾個 Frame。綠色線越高代表 FPS 越高,如果是動畫盡量要達到 60 FPS,綠色線上有紅色代表可能出現卡頓。
  2. CPU 代表消耗 CPU 資源執行哪些工作
  3. NET 比較少用,通常看 Network Tab 比較清楚

(3) 火焰圖: 這部分包含多個面向的詳細資料,我主要看的地方只有 Network 和 Main 而已。Network 看資源下載的順序,Main 看資源執行的順序。

  • 舉例,我們可以藉由下面火焰圖的 Network section,看到 HTML 檔下載完成後緊接著 Main section 的 HTML parsing,在執行過程中先遇到放在 head 的 CSS 並發出 HTTP request 請求 CSS 資源,後遇到放在 boby 尾端的 JS 再發出 HTTP request 請求 JS 資源。

Metric Image 04

(4) Details: 在火焰圖中點擊中意的事件,該事件的詳細資料會被顯示在 Detail 區塊。這個部分的圓餅圖總結、Call Tree 內每個 Activity 的耗時, Rendering 的 repaint flashing 和 Layout borders 標示都很有用!

瀏覽器運作簡介

簡單的瀏覽器架構如下:

Metric Image 05

  1. User Interface 是使用者看到的 UI 介面
  2. Browser Engine 負責與 Data Storage (localStorage, Cookies…) 溝通和操作 Render Engine,Firefox 的 Gecko engine 和 Safari / Chrome 的 WebKit engine 都是 Browser Engine
  3. Render Engine 是瀏覽器核心,為 Single thread,會一直循環等待事件觸發任務,它負責三種工作:

    • UI Backend: 渲染 (Paint) 頁面 (Single thread)
    • JS Engine: 負責運行Javascript (Single thread)
    • Network Component: 網路資源請求 (含HTTP Request / WebSockets / WebRTC),可同時發出多個請求

我們的重點在於頁面是如何被渲染出來給使用者觀賞的,也就是 UI Backend 的部分。當 Network Component 接收到 response 資源時,若該資源是 HTML 會被 UI Backend 解析成 DOM Tree;若該資源是 CSS 會被 UI Backend 解析成 CSSDOM Tree;若該資源是 JS 則會交給 JS Engine 處理。

DOM 和 CSSDOM 會被拿來建構 Render Tree,瀏覽器會根據 Render Tree 執行三段過程: Layout (版面佈局) –> Paint (繪製內容) –> Composite (圖層合併) 來完成 Frame 的繪製,如下圖。

Metric Image 06

這裡要特別提到 CSS 和 JS 的阻塞特性:

  • Javascript - parser blocking:當執行 JS 時,HTML / CSS 都會停止解析直到 JS 完成。其原因是 JS 擁有改變 HTML / CSS 的能力,故瀏覽器被設計成等待 JS 執行完後再繼續解析 HTML / CSS,避免無用的 HTML / CSS 解析。
  • CSS - render blocking:當執行 CSS 時,HTML可以繼續被 parsing,但 render tree 的建構會被暫停。因為 render tree 有 DOM 和 CSSDOM 這兩個來源,瀏覽器會等待整個 CSS file 的 CSSDOM 解析完後,再產生 render tree。

以瀏覽器的角度,會希望越快讓使用者看到畫面越好,所以它不會全部的 HTML 解析完才 Paint 頁面,而是將任務切成很多塊,解析完一部分就直接渲染到頁面,導致網頁擁有漸進出現的視覺效果。

時時樂頁面觀察

有了以上觀念後,我們再來對照看看真實網頁的頁面渲染過程。開啟 Dev Tool 後,建議禁用所有 chrome extension 來避免分析干擾,由下圖的 Main section 可以觀察到,chrome extension script 也會造成 parser blocking,安裝Disable Extensions Temporarily可以方便我們禁用 chrome 插件。

Metric Image 07

在開測之前,先簡單介紹這個頁面的架構。本頁面是採用 React + Redux 的 isomorphic app 架構,畫面大部分的 HTML 標籤和 store 的部分資料已經包含在 HTTP response 中 (server side render),isomorphic app 的好處有避免敏感的 API endpoint 露出、讓 First Meaning Paint (FMP) 的時間快一點、SEO 較好 (給搜尋引擎較多 HTML 資訊) 等…

大部分的 server side render 都會包含到 hero element (重點元件) 的內容,我們可以藉由勾選 disable javascript 來禁用本頁面的 JS,觀察 server side render 出來的 HTML 畫面長什麼樣子。

Metric Image 08

下圖是沒有執行任何 JS 的時時樂頁面,由此我們可以知道標籤列以下的內容是 client side render;標籤列以上的大 Banner 可能就是本頁的 hero element。

Metric Image 09

如果妳嘗試點擊標籤列會發現根本無法切換標籤,這是因為 client side 的 JS 被拔掉導致 onClick handler 沒有被附加到 HTML 元件上,使用者因此無法和元件互動,只能閱讀頁面內容。所以我們會建議在撰寫 React Component 時多使用原生 HTML tag 擁有的功能,像是要做 hyperlink 就要用 <a href=”” > 而不是 <div onClick={this.clickHandler} >,讓使用者在等待 client side JS 跑完之前,能和頁面做一些簡單互動。

接著我們回到設定,將 disable javascript 取消掉並 reload,會看到畫面由下面的左圖變成右圖。

左邊server side render,右邊加上client side render

本頁面的 main JS (rushbuy.js) 光是下載就花了 250ms,執行約花 500ms,兩者加起來共約 750ms。故使用者只能看著畫面乾瞪眼,直到 750ms 後才能和畫面做互動,很可能造成不好的使用者體驗。

Metric Image 12

效能指標

由上述經驗,我們可以總結出幾個會影響到使用者體驗的時間因子:

  1. 使用者多快能看到畫面?(Is it happening?)
  2. 使用者多快能看到有意義的畫面?(Is it useful?)
  3. 使用者多快能和畫面做互動?(Is it usable?)
  4. 使用者在與畫面互動的過程是否順暢?(Is it delightful?)

第一點和第二點的時間越快對使用者越好;第二點與第三點之間的時間差如果太大,使用者點擊畫面時會沒反應,或是造成卡頓,導致用戶體驗變差;第四點必須直接靠觀察 Performance Tab 分析,沒有相應的指標,偵錯範例可以參考這一篇,寫得非常清楚。

下面介紹幾個跟上述因子相關的效能指標,由 Google 提出!詳細說明可以參考這篇 User-centric Performance Metrics

  • First Paint (FP):當第一個 pixel 畫到畫面上的時間 (First Fame time),下圖是時時樂頁面的FP畫面。

Metric Image 13

  • First Meaning Paint (FMP):hero element 出現在畫面上的時間,hero element 由我們開發者自己定義,Dev Tool 會用黃色線標示出幾個候選的 hero element 給我們參考,如下圖。

Metric Image 14

  • Time to Interactive (TTI):Google 將這部分的評估劃分為兩個指標 (TTFI、TTCI),目前還在 Beta 階段,詳細計算方式可以參考其文件。我個人認為 TTFI 和 TTCI 沒那麼好用,不如直接取網頁的主要的 JS 所執行完的時間當作 TTI。下圖的 rushbuy.js 就是時時樂頁面最主要的 JS script,它執行完後就能應付此畫面大部分的互動行為。

Metric Image 15

以上三個都是和時間相關的效能指標,但使用者的感官體驗不只與時間相關,也與畫面漸進變化的過程有關。如果頁面在渲染過程中跳來跳去,就算渲染速度很快,也會讓使用者感到不舒服,Perceptual Speed Index / Speed Index 就是能幫助開發者評估使用者視覺體驗的指標。

  • Perceptual Speed Index / Speed Index (PSI/SI): 此數值能透過 Google LightHouse 獲得,它除了考慮時間,也會拿畫面截圖做分析比對,數字越小代表視覺體驗越佳。

Chrome Dev Tool 所標示出的指標線

Metric Image 16

依照上圖的標示依序看,橘色線是 First Meaning Paint candidate,是 Chrome Dev Tool 建議我們的 FMP 時間,可能會有一到多個,由開發者自己決定要取哪個時間作為 FMP;綠色線是 First Paint (FP),是第一屏 (Frame) 的時間點;藍色線和紅色線是前人常用的舊指標,藍色是 DOMContentLoaded event,會在 HTML 解析完呼叫,可以當成 Server side code 完成解析的時間,紅色線是 Load event,會在所有資源 (不包含 Async 等 Non-Blocking 資源) 解析完後觸發,時間大約會在 TTI 附近,可以用它作為 TTI 的參考。

結語

前端工程師追求給網頁使用者最好的互動體驗,了解瀏覽器運作和效率測量工具,能讓我們對自己作品的品質更有信心,共勉之XD


參考

[影片推薦]瀏覽器中Javascript的運作機制

介紹瀏覽器渲染步驟中Javascript的部分,包含Event loop的說明 Continue reading