Categories
程式開發

前端加載優化實戰,減少頁面渲染時間66%


乾貨概覽

說到頁面性能優化,我們常常想到 首次加載、交互響應和渲染幀率 等頁面性能指標。為了給用戶流暢的使用體驗,我們常常針對這些指標進行優化。接下來,我們以AIOps團隊智慧機場項目為例,介紹我們如何將首次加載時間為4000ms的頁面優化至1350ms的,文章所介紹的加載優化方法具有一定參考作用,希望能對大家有所幫助。

項目簡介

智慧機場項目是一個根據實時航班,對機場機位資源進行動態分配的智能係統。其主要目的是將航班盡量停靠在廊橋機位,增加廊橋機位使用率,減少旅客登機、下飛機時間,同時避免航班因延誤等因素對機位的衝突使用,機位的分配情況-甘特圖頁面如圖1所示:

前端加載優化實戰,減少頁面渲染時間66% 1

圖1 智慧機場甘特圖

圖中區域1表示不同的機位和機位類型,用​​戶可以上下滑動或者通過篩選獲得不同機位的信息;區域2為時間軸;用戶可以滑動時間軸,選擇不同的時間段,同時也可以進行縮放操作,來擴大或減小查詢範圍;區域3為內容區,展示不同機位在對應時間段內的航班信息,每一個航班使用條狀圖展示,條狀圖顏色表示航班狀態,我們分別用幾種顏色表示飛機到達、起飛、衝突、返航等屬性。整個頁面展示與用戶交互過程中,甘特圖需要根據用戶的篩选和操作實時的從後端多個接口中加載數據並進行渲染展示。

該頁面與大多數大數據展示頁面遇到的性能問題一致,一個是請求的接口多帶來請求等待性能下降,另一個是展示的元素多帶來的渲染性能下降。在第一版甘特圖中,頁面的平均加載時間長達4000ms,下面我們通過通用方案和自定義方案兩方面來看一看,我們是如何將加載速度降低到1350ms的。

通用優化方案

首先,我們對網頁的整個渲染流程來分析,哪些因素會影響網頁的加載速度,以及每個階段對應的常見解決方案分別是什麼。

我們可以將網頁加載大致分為三個階段,分別為請求階段,資源處理階段,以及頁面渲染階段。甘特圖在其中請求耗時約1600ms,資源處理耗時約2200ms,頁面渲染耗時約200ms;

  1. 請求階段 主要是資源、數據請求,網絡狀況及數據量對該部分影響較大,主要優化手段為 優化網絡和對數據壓縮。在請求階段,我們通過請求數據壓縮的手段,將耗時由1600ms減少到1000ms;
  2. 資源解析階段 主要是對請求下來的資源和數據進行處理,數據規模及處理方式對該部分影響較大,主要優化手段減少數據處理耗時;在資源解析階段,我們通過 降低處理數據操作複雜度,將耗時由2200ms減少到了2100ms。
  3. 渲染階段 主要是將處理後的數據渲染在頁面上,頻繁的重繪和重排對該部分影響較大,主要優化手段是 減少重繪和重排。在此階段我們未做優化。

在甘特圖中,我們通過上述通用手段,將總耗時由4000ms減少到3300ms,但是加載速度仍然較慢。所以我們又在數據請求階段、資源處理階段的組件初始化及可視化視圖渲染計算三個方向進行優化,通過對這三個方向進行優化,我們將耗時由3300ms減少到了1350ms,下面我們將詳細對這三方面的優化做介紹。

自定義優化方式

為了進一步降低加載時間,我們利用性能分析工具對網頁加載進行進一步分析,發現頁面加載過程中,數據請求、組件初始化及渲染計算過程耗時比較長。我們分別對三個過程進行優化:

數據請求部分使用並行請求+請求時執行頁面邏輯的方式進行加載速度優化,對於 數據請求多、頁面處理業務複雜 的類似頁面可以參考此類方法;

組件初始化部分使用延後綁定比較大的數據進行加載速度優化,對於頁面 需要監聽比較大的雙向綁定數據 等類似場景可以參考此方法;

渲染計算部分使用盡量減少圖形繪製來提升渲染計算速度,對於使用 ECharts繪製比較複雜的自定義圖形 的頁面可以參考此方式;

接下來,我們將詳細解說加載速度優化的具體方案。

1 數據請求優化

在智慧機場項目中,頁面渲染需要請求用戶信息、自定義展示配置等信息和數據,因此請求較多,前端採用串行請求的方式會消耗比較長的時間,因此這裡採用 並行發送請求 的方式進行數據請求,如下:

前端加載優化實戰,減少頁面渲染時間66% 2

圖2 async第三方庫並發發送請求

第一版甘特圖頁面渲染需要發送3個請求,在增加配置後,請求數增加到9個。通過並行請求的方式,頁面在發送3個請求時,耗時1000ms,增加到9個請求後,串行耗時為3400ms,通過並發請求的方式,9個請求耗時降低到440ms。

但在使用async第三方庫請求的過程中,CPU只能處於等待狀態。為了充分的利用CPU,我們採用ECMAScript 6標準的async函數來對此進行改造。

有別於async第三方庫使用回調函數的形式做串行處理,ES6使用await關鍵字等待異步函數返回Promise對像做串行處理。首先我們基於ES6代碼改寫async第三方庫實現:

前端加載優化實戰,減少頁面渲染時間66% 3

圖3 async函數異步使用await關鍵字

然後,我們可以在發送請求時,先不使用await關鍵字,僅保存發送請求的Promise對象,在異步請求後端接口過程中,首先進行頁面初始化的渲染操作,然後再將異步請求的返回結果進行渲染處理,實現如下:

前端加載優化實戰,減少頁面渲染時間66% 4

圖4 改進後利用異步請求等待時間做初始化處理

通過這樣的改造,我們在並發請求多個數據的同時,利用請求的間隙,完成繪製初始化、默認配置計算、時間初始化等工作。充分利用CPU資源,進一步減少js執行耗時340ms。

通過以上優化,整個加載過程累積減少耗時900ms,頁面加載時間由3300ms降至2400ms左右

2 組件初始化優化

智慧機場項目是採用NoahV運維前端展現層框架,詳情戳這裡)開發的,該框架基於Vue實現,並採用組件化的思路進行頁面元素構建。同時,甘特圖的繪製是通過ECharts進行繪製的。

在甘特圖界面中,用戶需要實時調整時間段,獲得對應時間段的航班分配情況,故在用戶移動時間軸的時候,會根據選擇的時間不斷更新航班的分配情況,從後端獲得對應時間段的航班數據,然後將請求到的數據傳入頁面組件。

基於Vue的雙向數據綁定的特徵,當數據發生變化的時候,Vue會構建監聽對象去監聽數據,再用ECharts重繪甘特圖。如下是組件監聽數據的工作流程。

前端加載優化實戰,減少頁面渲染時間66% 5

圖5 組件數據監聽工作流程

從圖5看,當數據傳入的時候,為了數據和頁面雙向綁定,需要構造監聽對象,構造監聽對象所消耗的時間是根據數據複雜程度決定的。數據越複雜,構造監聽對象所消耗的時間越多。

為了加快頁面加載速度,我們在首次加載數據時直接渲染圖形,減少構建監聽對象耗時。在渲染頁面完畢後,延遲構造監聽對象。流程如圖6:

前端加載優化實戰,減少頁面渲染時間66% 6

圖6 改造組件數據工作流程

基於這樣的流程優化,航班、機位、待分區航班和待分區機位數據在渲染視圖前減少監聽對象的構建,耗時相應的分別平均減少約230ms、210ms、167ms和151ms,累積減少耗時約800ms。頁面加載耗時由2400ms降低至1600ms

3 渲染計算優化

前面我們介紹了頁面渲染時減少構建監聽對象的過程加快頁面渲染時間,接下來我們對可視化渲染視圖部分進行進一步分析。

可視化視圖渲染耗時隨數據量的增加而增大,我們對視圖渲染流程做進一步的分析,看哪些流程受到數據量影響較大,渲染視圖計算可分為6個過程,如圖7:

前端加載優化實戰,減少頁面渲染時間66% 7

圖7 渲染計算流程

針對上述流程,我們分別設置不同數據量(表一第一列)及單個甘特條包含不同圖形數目(表一第二列),然後通過分析工具查看各個階段的耗時情況,具體如表1 :

表1 數據量及每條數據圖形對渲染計算各階段影響

前端加載優化實戰,減少頁面渲染時間66% 8

通過表1,我們可以分析得出,數據量及每條數據所含圖形數目對於階段1、4、5、6(配置轉換、圖層刷新、圖層渲染和圖層合併)沒有明顯影響。對於階段2(圖層初始化),在只有一個圖形和一條數據時,耗時較短,其他情況耗時相差不大;而對於階段3(圖形繪製計算階段),可以明顯看出,單條數據所包含圖形越多,計算時間越長(表1第五列)。因此我們在這裡選擇減少繪製圖形數目(類似減少頁面DOM節點)來減少渲染計算的耗時。首先,我們對甘特條完整圖形進行拆解,如圖8左側甘特條拆解所示:

前端加載優化實戰,減少頁面渲染時間66% 9

圖8 甘特條圖形拆分

由圖8所示,A表示發布狀態、B的顏色表示進港航班狀態、C的顏色表示出港航班狀態,D表示播報狀態,整個條狀圖使用4個圖形繪製。

為了減少繪製圖形,我們將這4個圖形合併為一個圖形。首先,我們將A、D兩個圖形分別和B、C進行合併,這裡採用設置矩形頂角半徑的方法來繪製弧度,實現如圖9:

前端加載優化實戰,減少頁面渲染時間66% 10

圖9 利用頂角弧度替代弧形A、D

然後,我們利用分段顏色樣式將B、C兩部分合併,實現如圖10:

前端加載優化實戰,減少頁面渲染時間66% 11

圖10 利用分段顏色合併B、C

這樣,我們分別通過矩形頂角弧度設置和分段顏色設置,將A、B、C、D四個圖形合併成了一個,如圖8中X;

三個外框線E表示鎖定狀態、F表示分割狀態、G表示預測狀態,我們將三個框線圖形合併為一個,顏色樣式同樣使用上述分段顏色控制,合併後如圖8中Y。

這樣,我們就將一個條形圖的7個圖形減少為2個。如圖8中右側圖。

通過合併圖形元素,平均每條數據渲染計算的時間減少了2.5ms,頁面平均展示100條數據,累積減少耗時約250ms。頁面加載耗時由1600ms降至1350ms左右

總結

對於智慧機場項目,我們分別通過 通用解決方案、數據優化、組件初始化優化及渲染計算優化,分別降低頁面加載耗時700ms、900ms、800ms、250ms,累積約2650ms。頁面加載耗時由4000ms降低到1350ms,耗時降低66%。有效的減少了頁面渲染的時間,優化了系統的響應速度,提升了用戶體驗。整體上,性能優化首先是通過性能分析工具來找到性能瓶頸,再針對每項進行優化。大致會從數據請求,資源解析,數據渲染方向做優化,然後再結合選型框架的特徵,進行更細粒度的優化。

作者介紹

張海超 百度高級前端研發工程師

負責百度智能運維產品(Noah)、智慧機場等前端研發工作,對前端性能優化有廣泛的實戰經驗。

本文轉載自公眾號AIOps智能運維(ID:AI_Ops)。

原文鏈接

https://mp.weixin.qq.com/s?__biz=MzUyMzA3MTY1NA==&mid=2247485369&idx=1&sn=c608eb3bf3a0fde1b35160edd6bf545d&chksm=f9c37e70ceb4f76670615cf8ffd45ca7ed230131b70253075d93da8f9a8aa971503793242a07&scene=27#wechat_redirect