移動端瀏覽器性能優化探索

在移動端的頁面開發過程中,我們經常提及頁面性能優化、消除頁面卡頓的話題,如何 · 確定優化策略,我們首先應當對頁面卡頓的行爲有所認知。

前言

頁面的卡頓現象可以比較明確的分爲三個類型,分別是 “畫面撕裂” 、“丟幀不流暢”、“長時間未響應”。

“畫面撕裂 “ 現象給人直觀的感覺是頁面返回內容不一致,而造成這種現象的原因在於屏幕的刷新機制,屏幕的刷新遵循 “Z” 字刷新的方式,因此同一幀的數據在上屏時存在一定的時間差,當幀率大於刷新率時,屏幕對前一幀的數據上屏尚未結束而後臺對後一幀的數據處理合成完畢,此時屏幕完成上屏的數據將會採用後一幀的數據,造成人眼同一時刻觀測的畫面數據來源於不同幀的現象,給人以撕裂感。

” 畫面丟幀 “也被稱爲 Jank 現象,給人的直觀感覺是畫面不流暢,在動畫或滾動時出現短暫停滯,而造成丟幀的原因在於屏幕每隔 16ms 發出一個 VSync 信號,在正常幀的流程中,CPU 接收到 VSync 信號後會先通過交換指針的方式進行前後緩衝區的數據同步(該過程時耗忽略不計)然後開始新一幀數據合成,當幀率小於刷新率時,下一個 VSync 信號到來時可用於交換的幀數據還沒有通過 CPU 計算合成,此時前後緩衝區的數據不會發生交換,因此屏幕內出現了連續兩幀使用同一幀數據渲染,給人以停頓和不流暢的感覺。

"長時間未響應" 指的是畫面長時間等待,等待網絡請求或其他事件處理,這種情況通常並不是由於幀渲染導致的,但等待時長如果違背了 RAIL 模型,會嚴重阻塞(BLOCK)用戶行爲,該類型的卡頓通常會採用別的指標進行衡量。

  1. Response 響應時間:系統應當在 100ms 內對用戶的輸入作出響應,這種輸入表示任何用戶的交互行爲,比如輸入文本、點擊、切換表單、開啓動畫等。在不阻塞用戶交互行爲的前提下可以對一些耗時昂貴的工作進行預運算,對於耗時 500ms 以上的工作項應當通過信息反饋提前告知用戶。

  2. Animation 動畫:對於動畫的交互,如 touchmove、scroll 等需要在 16ms 內作出響應,而動畫的幀率期望能夠達到每秒 60 幀,即折算一幀 16.6ms,而實際上渲染一幀的動畫過程瀏覽器還存在着大量的樣式計算、佈局計算、線程調度、圖層合成、光柵化等過程,因此純 JS 的線程執行耗時應當控制在 10ms 內。

  3. Idle 最大化空閒時間:空閒時間可以用來完成優先級不高的任務,通過 50ms 爲基準將延遲任務進行分片分組執行,目的時爲了能夠預留 50ms 的空閒時間給到主線程來對用戶的輸入進行即時響應,從而完成 100ms 內響應用戶的標準。

  4. Load:1s 內完成站點加載。

上文中提到的很多名詞概念,在此也做簡單介紹。

  1. 幀率(FPS):指的是一秒內合成幀的數量,常用 FPS 來描述,60FPS 表示一秒內合成 60 幀。

  2. 刷新率(Hz):指的是一秒內屏幕的刷新次數,安卓機通常爲 60Hz。

  3. VSync(垂直同步):是一種定時中斷技術,時間間隔爲 16.6ms,VSync 信號保證了畫面內的數據來源同步,磨平了屏幕刷新方式帶來的上下屏數據來源的差異性。通常與雙緩存、三緩存技術共同解決 ” 畫面撕裂 “ 帶來的卡頓。此處介紹一個可用於測試設備是否支持 VSync 的在線工具 設備測試 VSync。

  4. 雙緩存機制:通過設計兩種類型的緩存器 Back Buffer、Frame Buffer 分別爲 CPU 數據處理以及屏幕讀取數據服務,解決了幀渲染過程中同時存在的讀寫邏輯衝突。

  5. 三緩存機制:CPU 與 GPU 在 Back Buffer 的使用權上存在競爭關係,導致 GPU 佔用時間段內 CPU 線程處於閒置狀態,從而導致合成幀耗時較長,三緩存將 CPU 與 GPU 對緩存器的使用狀態也進行了隔離。

如何衡量卡頓

FPS 與卡頓的關係

一般來說,我們通過頁面的 FPS 來作爲衡量頁面卡頓的指標,但是用 FPS 來做卡頓的描述並不精確,舉個例子:

  1. 電影的播放的 FPS = 24 , 但是在電影播放過程並不會出現卡頓現象,說明了 FPS 低於 30 也不表示畫面卡頓,從定義上來看 FPS 僅描述了一秒內的畫面繪製次數,如果一秒內頁面沒有任何繪製的需求,FPS = 0  是很正常的。

  2. 對應的,FPS = 60 的頁面如果在前 200ms 僅僅完成了首幀的渲染而剩餘 800ms 完成了剩餘 59 幀的渲染,保證了一秒內的幀數 , 但是仍然會帶來卡頓的現象。

新的衡量指標

SM(SMoothes) 是 Android 端提出的相比於 FPS 更加準確的衡量卡頓現象的指標,SM 更好的考慮了單位時長內的有效幀數佔比,SM 計算公式如下:

SM = FPS * (單位時長的總幀數 - 單位時長丟幀數) / 單位時長總幀數

瀏覽器動畫渲染

爲了能夠更好的跟蹤動畫渲染過程的卡頓,我們應該更加清晰的去認知瀏覽器渲染的原理和過程,動畫渲染的原理大圖如下:



對上圖進行鏈路總結如下:

  1. CPU 負責處理 複雜的控制邏輯以及數據邏輯,在瀏覽器的渲染過程中生成 DOM 樹、CSSOM 樹、樣式計算、佈局計算、圖層生成等,最後將矢量數據提交給合成器以及 GPU。

  2. GPU 接受圖層圖塊信息,並基於強大的硬件能力對圖層進行分割切片、柵格化。GPU 從結構上擁有更多的 ALU 單元,更擅長大量重複的計算以及矩陣變換,能夠以流式並行的模式快速完成位圖繪製,並將紋理數據存入緩存器。

  3. 顯示器通過 VSync 信號強制拉齊幀率與刷新率,當信號來臨時訪問前緩存器拿到最新的位圖數據並用於上屏。

GPU 扮演的角色

我們常說的硬件加速其實是通過 GPU 的特性來緩解 CPU 的計算壓力,相比於 CPU,GPU 擁有更多的 ALU(算數邏輯單元),其特有的流式並行計算模式在矩陣變換的計算上有天然的優勢,同時採用 GPU 的硬件加速可以對待處理的元素進行圖層提升,實現了在畫布更新過程中隔離非合成元素的目的,等到生成結束後通過相應位置的替換完成圖層的合成,從而減少了 CPU 線程內迴流和重繪的計算過程。

值得注意的是,瀏覽器本身爲我們完成了很多優化的策略,比如在使用 transform、opacity 屬性的時候瀏覽器會自動開啓 GPU 加速,因此更推薦在動畫過程中通過上述屬性進行處理。除此之外,通過 will-change 定義的 CSS 屬性值,瀏覽器也會預先將其關聯的元素提升到新的圖層,從而避免刷新屏幕時出現迴流和重繪的過程。

合理避免迴流和重繪

事實上,是否避免了迴流和重繪的過程取決於對應的元素是否真正被提升到了合成層(Composite Layer)。即使使用了 transform、opacity 兩個屬性,如果瀏覽器不支持硬件加速導致圖層沒有被提升,那麼在更新的過程中仍然會因此迴流和重繪。

在此對常用於提升圖層的方法進行羅列:

  1. 3D transforms: translate3d, translateZ 等;

  2. video, canvas, iframe 等元素;

  3. 通過 Element.animate() 實現的 opacity 動畫轉換;

  4. 通過 СSS 動畫實現的 opacity 動畫轉換;

  5. position: fixed;

  6. will-change;

  7. filter;

  8. 有合成層(Composite Layer)後代同時本身 overflow 不爲 visible(如果本身是因爲明確的定位因素產生的 SelfPaintingLayer,則需要 z-index 不爲 auto)

瀏覽器工作流程

到此我們明確了在瀏覽器動畫繪製過程中 CPU 以及 GPU 扮演的角色,爲了更加清晰的明確一幀內 CPU 與 GPU 負責的具體工作,我們需要對瀏覽器內核的工作有一定的瞭解。

首先,瀏覽器是多進程工作的,進程結構如下:

我們常說的瀏覽器內核其實就是渲染進程(渲染引擎)。渲染引擎將從網絡層獲取請求的文檔內容並解析渲染,整個渲染引擎的工作流程是漸進的,渲染引擎的工作流程如圖所示:

對於其中的每一個部分展開解釋有些複雜,本文不多做贅述。

本文還是更加聚焦於畫面渲染的 Layout 以及 Painting 過程,從這個角度來看,單幀內的渲染引擎主線程過程的 Pipline 如下圖:

引入 GPU 加速計算後的主線程 Pipline 如下圖:

對上述 Pipline 的各節點解讀如下:

  1. Input event Handlers 代表瀏覽器的輸入事件回調,該事件會被瀏覽器進程(Brower Process)捕捉,隨後瀏覽器進程會將事件類型(如 touchstart)及其座標發送給渲染進程(Renderer Process),渲染進程通過查找事件目標並運行附加的事件偵聽器來處理事件。

  2. requestAnimationFrame 允許定義一個回調函數,可提供給用戶在當前幀佈局計算以及繪製之前做一些預處理操作。

  3. CPU 在 ParseHTML  過程負責將瀏覽器不能識別的 HTML 文本轉換爲瀏覽器能識別的 DOM 對象。

  4. CPU 在 RecalcStyles 過程會解析 CSS 文件,依據 CSS 的樣式繼承以及層疊規則計算 DOM 節點的每一個元素的具體樣式,並保存在 ComputedStyle 結構中。

  5. CPU 在 Layout 過程基於 DOM Tree 以及 Compouted Style 計算元素佈局信息並生成 Layout Tree(RenderObject), 在該過程中不可見的 DOM 節點會被忽略,例如 head 標籤下的全部內容以及 display = none 的 DOM 節點。

  6. CPU 在 Update Layer Tree 過程負責將相同 z 空間座標的 Layout Tree(RenderObject) 歸併到相同的 Paint Layer(RenderLayer),從而保證頁面元素的合成順序。通常情況下,並不是佈局樹的每個節點都包含一個圖層,如果一個節點沒有對應的層,那麼這個節點就從屬於父節點的圖層,但不管怎樣,最終每一個節點都會直接或者間接地從屬於一個層。

  7. CPU 在 Paint 過程幹了兩件事:第一件事是完成繪製(Painting),即生成新生成 / 修改元素的繪製信息,包括圖形信息,文本信息。第二件事是完成柵格化(Rasterization),對 Painting 的繪製信息進行消費,對於沒有 GPU 加速的情況下,瀏覽器會通過 CPU 進行軟件柵格化,軟件渲染器沒有使用 GL 將內容紋理塊複製到後臺緩衝區,而是使用 Skia( 2D 繪圖庫)的軟件光柵化器來執行復制 (並執行任何必要的矩陣計算和裁剪)。

  8. CPU 在 Composite 過程將圖層信息提交(commit)到 合成線程(Compositor Thread) 中,在此線程中會對圖層進行分塊生成圖塊(圖塊是柵格操作的單位)同時藉助 GPU 對額外的屬性(如:will-change 聲明的元素,啓用硬件加速的 canvas)進行處理(圖層變換、合成)。

  9. GPU 在 Rasterize 過程對圖塊紋理進行 柵格化 處理。

  10. 合成線程會在所有圖層被 Rasterize 後打包發送到 GPU 進程,此時標誌着一幀結束。

  11. 頁面的所有信息在 GPU 內被處理後傳入雙緩存的 Back Buffer 中,下次垂直同步信號到達後互換前後緩存區位置,完成上屏。

到此,可以回答本章節開篇提出的問題,CPU 給 GPU 傳遞的數據是經過佈局、繪製計算的到的矢量圖信息,而 GPU 只負責對矢量圖進行像素化(光柵化)以及着色後將其存放到幀緩存區,等待下一個 VSync 信號的同步。

解決方案

回到移動端本身的問題,低端機面臨的性能瓶頸問題往往由於其硬件能力不足導致的,如 CPU 性能(主頻大小、Cache 容量)、內核數、內存大小、DRAM 大小、是夠支持 GPU 加速以及 GPU 核數等。對於同樣的頁面邏輯,在低端機上執行,往往會帶來更高的 CPU 佔有率從而導致幀數丟失、更高的內存佔有率從而帶來更多的數據交換損失,而一些不支持 GPU 的機型中,單幀內的動畫會依賴 CPU 進行軟件渲染,這個過程會大量佔用 CPU 主線程從而帶來丟幀。

在瞭解低端機面臨的瓶頸問題後,我們應該通過以下策略最大限度的降低性能損耗:

  1. 開啓適當的硬件加速(GPU 加速),合理使用 CSS 屬性進行動畫繪製,如 transform、opacity、filter 等。

  2. 採用 will-change 對比較複雜的元素處理進行單獨圖層的提升(切忌對所有元素使用,過量的圖層會加劇 GPU 合成時的功耗)。

  3. 最小化動畫的範圍,可以有效減少幀數據(位圖)的大小,降低 GPU 訪問主存的時間損耗。

  4. 使用脫離文檔流的方式對元素進行動畫,減少迴流。

  5. 避免通過父級元素對子元素進行訪問,樣式的訪問鏈路過程會加劇樣式樹計算時的時間損耗。

  6. 儘可能少的訪問 offsetWidth、 top 等元素樣式屬性,因爲這些屬性會引發迴流和重繪,如果必須訪問時,可以進行數據緩存,同時可以在 rAF 階段進行訪問,因爲 rAF 後瀏覽器會進行佈局的 recalculate 。

  7. 對於沒有 GPU 加速的機型,可採用降低動畫的影響範圍,降低紋理的尺寸的方式等加速主線程,從而提升頁面響應速度。

  8. 長任務切片,將連續串行的任務通過優先級設置和任務調度的方式切割,從而減少長任務佔用主線程時無法及時對用戶行爲作出響應。

團隊介紹

我們是大淘寶技術營銷與平臺策略技術團隊,是大淘寶技術的核心部門之一,負責手機淘寶核心用戶產品——搜索、拍立淘,並且支撐雙 11、618 等大型活動,聚划算、百億補貼、天天特賣、淘寶好價等營銷產品。這裏有基於商品的搜索引擎建設對搜索與終端智能業務的探索,還有招商、選品、搭建、投放的活動支撐鏈路建設以及優惠券、跨店滿減、直降、會員卡等多種營銷工具的創新和沉澱。我們的目標是以平臺化、數據化、智能算法等方式支撐大淘寶爲主的集團核心平臺營銷場景,全力爲淘寶天貓打造有樂趣的購物體驗,爲數億用戶提供優質服務。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/SKO3vZXTTYE2pRCFaT5H3A