前端效能優化--渲染篇

語言: CN / TW / HK

對於內容複雜和變更頻繁的前端應用,頁面渲染也常常是效能優化的核心場景。

前面我有給大家整體地講過 《前端效能優化–方案歸納篇》 ,其實裡面已經囊括了大多數場景下的一些效能優化的方向。關於載入流程相關的優化,也有在 《前端效能優化–載入流程篇》 一文中進行詳細的介紹。

本文主要圍繞頁面渲染相關的內容,來進行效能優化分析。

首屏渲染

說到頁面渲染,首屏的渲染顯然是最首要的。其實前面在歸納篇也有介紹,首屏載入優化核心點在於: 將頁面內容儘快展示給使用者,減少頁面白屏時間。

首屏渲染包括了首屏內容的載入和渲染兩個過程。

首屏內容載入

對於首屏載入過程,我們可以通過以下方式進行優化:

  • 使用骨架屏進行預渲染
  • 對頁面進行分片/分屏載入,將頁面可見/可互動時間提前
  • 優化資源載入的順序和粒度,僅載入需要的資源,通過非同步載入方式載入剩餘資源
  • 使用差異化服務,比如讀寫分離,對於不同場景按需載入所需要的模組
  • 使用服務端直出渲染,減少頁面二次請求和渲染的耗時
  • 使用秒看技術,通過預覽的方式(比如圖片)提前將頁面內容提供給使用者
  • 配合客戶端進行資源預請求和預載入,比如使用預熱 Web 容器
  • 配合客戶端將資源和資料進行離線,可用於下一次頁面的快速渲染

這裡提到了很多的方向,但是否每個優化點都適用於自身的專案中,需要結合專案本身做調研和驗證。舉個簡單的例子,最後兩條優化點明顯是基於有自研客戶端的前提下,需要配合客戶端一起做優化才可以實現。

實際上,對於首屏內容的優化,前端開發在專案中更常用的點是骨架屏、資料分片/分屏載入、SSR DOM 直出渲染這幾種,因為這幾個優化點相對來說方向明確、效果明確、實現相對簡單。如果是想要對專案做差異化服務、做資源的拆分和優化,則可能隨著專案的複雜度增加,方案難度提升、實現成本也增長。

首屏內容渲染

對於首屏內容渲染的過程,更多時候我們是指瀏覽器渲染 HTML 的過程。該過程可以優化的點也是我們常常提及的,瀏覽器渲染頁面的優化過程,比如:

<head>
<body>

以上這些,是我們在做首屏渲染時考慮渲染過程的優化點。雖然這些優化點屬於前端基礎和共識,也常常會出現在基礎面試中。

很多時候我們為了準備面試而學習了很多的知識和原理,卻容易在將知識和實踐結合的過程中忘記。越是基礎和簡單的點,反而往往會在實際寫程式碼的時候被忽略,直到效能出現了問題,這些基礎的優化點才會被注意到。

當然,首屏效能的提升,除了渲染相關的,也還有上一篇我們提到的載入流程相關的優化。

頁面更新

除了首屏內容需要儘快載入和渲染以外,當頁面內容需要更新的時候,我們也需要儘可能地減少更新內容渲染的耗時。

一般來說,頁面更新場景我們常常會關注使用者操作和頁面渲染。

使用者操作

頁面內容的更新,一般有兩種情況:

  1. 使用者自身操作(點選、輸入、拖拽等)的頁面響應。
  2. 實時內容的變更(比如聊天室的訊息提醒、彈幕等等)。

如果是使用者自身的操作,則我們需要及時地更新頁面內容,讓使用者感受到操作生效了。該過程應該是優先順序最高的,一般需要同步進行。因為如果有別的任務在執行而導致主執行緒阻塞,就容易造成頁面卡頓的體驗。關於卡頓相關的,我會另外再起一篇文章介紹,這裡就不過多展開啦。

至於實時內容的變更,優先順序更多會比使用者操作稍微低一些,也基本上都是非同步進行的。我們還可以考慮對變更內容做合併、批量更新,也可以考慮定時拉取最新內容更新的方式。

事件委託

對於使用者互動頻繁的場景,我們還得注意事件的繫結。相信很多人都瞭解過事件委託,如果在列表數量內容較大的時候,對成千上萬節點進行事件監聽,也是不小的效能消耗。使用事件委託的方式,通過將事件繫結在父元素上,我們可以大量減少瀏覽器對元素的監聽,也是在前端效能優化中比較簡單和基礎的一個做法。

事件委託是很常見的優化方式,需要注意的是,如果我們直接在 document.body 上進行事件委託,可能會帶來額外的問題。由於瀏覽器在進行頁面渲染的時候會有合成的步驟,合成的過程會先將頁面分成不同的合成層,而使用者與瀏覽器進行互動的時候需要接收事件。

如果我們在 document.body 上被綁定了事件,這時候整個頁面都會被標記。即使我們的頁面不關心某些部分的使用者互動,合成器執行緒也必須與主執行緒進行通訊,並在每次事件發生時進行等待。此時可以使用 passive: true 選項來解決。

頁面渲染

我們在頁面內容更新的時候,一般也可以考慮以下優化點:

  • 減少/合併 DOM 操作,減少頁面更新的內容範圍,減少瀏覽器渲染過程中的計算耗時
  • 對於頁面動畫,可以使用 CSS transition 能力,減少 DOM 屬性的修改
  • 使用資源預載入,在空閒時間,提前將使用者可能需要用到的資源進行獲取並載入(比如下一頁的內容)

DOM 操作合併

說到 DOM 操作的合併和減少,目前大多數前端框架都提供了虛擬 DOM 的能力(比如 Vue 和 React)。虛擬 DOM 本身就有對 DOM 操作和更新做優化,通過使用 JavaScript 物件模擬 DOM 元素,並在頁面需要更新時對更新的部分做 DOM Diff,儘可能地減少內容的更新頻率和範圍。

雖然現在大多數前端專案都離不開前端框架,也正因為這些框架本身已經做了很多的優化,所以我們常常會忘記和忽略掉這些注意事項。

但也從側面論證了,即使是很基礎的優化點也需要重視,即使是簡單的優化點也可以做出很棒的設計。

頁面滾動渲染

考慮到頁面滾動的場景,可能會出現效能問題的地方常常是長列表/頁面的渲染。

由於頁面內容過多,頁面的 DOM 元素數量也很多,容易造成頁面渲染的卡頓。在這樣的情況下,我們可以考慮僅渲染可見區域的部分,比如頁面內容超出滾動範圍之外,就可以進行銷燬,將頁面的 DOM 數量保持在一定範圍內。

結束語

本文主要圍繞頁面渲染和更新的過程,介紹了一些效能優化的方向。其實如果你有注意到,就會發現本文的內容大多數還是基礎和簡單的前端知識點。

還是那句話,前端基礎和原理知識基本上大多數開發都掌握了,但是要怎麼將這些知識在專案中發揮到最佳的作用呢?這才是我們工作中在不斷探索和學習,獲得經驗和成長的關鍵點。

紙上得來終覺淺,瞭解一些知識很簡單,但是要深入理解、熟練掌握後,再結合自身經驗將它發揮出來,才是其價值的完整體現。