做者簡介:張海超 百度高級前端研發工程師
負責百度智能運維產品(Noah)、智慧機場等前端研發工做,對前端性能優化有普遍的實戰經驗。前端
說到頁面性能優化,咱們經常想到首次加載、交互響應和渲染幀率等頁面性能指標。爲了給用戶流暢的使用體驗,咱們經常針對這些指標進行優化。接下來,咱們以AIOps團隊智慧機場項目爲例,介紹咱們如何將首次加載時間爲4000ms的頁面優化至1350ms的,文章所介紹的加載優化方法具備必定參考做用,但願能對你們有所幫助。後端
智慧機場項目是一個根據實時航班,對機場機位資源進行動態分配的智能系統。其主要目的是將航班儘可能停靠在廊橋機位,增長廊橋機位使用率,減小旅客登機、下飛機時間,同時避免航班因延誤等因素對機位的衝突使用,機位的分配狀況-甘特圖頁面如圖1所示:性能優化
圖1 智慧機場甘特圖網絡
圖中區域1表示不一樣的機位和機位類型,用戶能夠上下滑動或者經過篩選得到不一樣機位的信息;區域2爲時間軸;用戶能夠滑動時間軸,選擇不一樣的時間段,同時也能夠進行縮放操做,來擴大或減少查詢範圍;區域3爲內容區,展現不一樣機位在對應時間段內的航班信息,每個航班使用條狀圖展現,條狀圖顏色表示航班狀態,咱們分別用幾種顏色表示飛機到達、起飛、衝突、返航等屬性。整個頁面展現與用戶交互過程當中,甘特圖須要根據用戶的篩選和操做實時的從後端多個接口中加載數據並進行渲染展現。併發
該頁面與大多數大數據展現頁面遇到的性能問題一致,一個是請求的接口多帶來請求等待性能降低,另外一個是展現的元素多帶來的渲染性能降低。在初版甘特圖中,頁面的平均加載時間長達4000ms,下面咱們經過通用方案和自定義方案兩方面來看一看,咱們是如何將加載速度下降到1350ms的。框架
首先,咱們對網頁的整個渲染流程來分析,哪些因素會影響網頁的加載速度,以及每一個階段對應的常看法決方案分別是什麼。運維
咱們能夠將網頁加載大體分爲三個階段,分別爲請求階段,資源處理階段,以及頁面渲染階段。甘特圖在其中請求耗時約1600ms,資源處理耗時約2200ms,頁面渲染耗時約200ms;異步
在甘特圖中,咱們經過上述通用手段,將總耗時由4000ms減小到3300ms,可是加載速度仍然較慢。因此咱們又在數據請求階段、資源處理階段的組件初始化及可視化視圖渲染計算三個方向進行優化,經過對這三個方向進行優化,咱們將耗時由3300ms減小到了1350ms,下面咱們將詳細對這三方面的優化作介紹。前端性能
爲了進一步下降加載時間,咱們利用性能分析工具對網頁加載進行進一步分析,發現頁面加載過程當中,數據請求、組件初始化及渲染計算過程耗時比較長。咱們分別對三個過程進行優化:async
數據請求部分使用並行請求+請求時執行頁面邏輯的方式進行加載速度優化,對於數據請求多、頁面處理業務複雜的相似頁面能夠參考此類方法;
組件初始化部分使用延後綁定比較大的數據進行加載速度優化,對於頁面須要監聽比較大的雙向綁定數據等相似場景能夠參考此方法;
渲染計算部分使用盡可能減小圖形繪製來提高渲染計算速度,對於使用ECharts繪製比較複雜的自定義圖形的頁面能夠參考此方式;
接下來,咱們將詳細解說加載速度優化的具體方案。
在智慧機場項目中,頁面渲染須要請求用戶信息、自定義展現配置等信息和數據,所以請求較多,前端採用串行請求的方式會消耗比較長的時間,所以這裏採用並行發送請求的方式進行數據請求,以下:
圖 2 async第三方庫併發發送請求
初版甘特圖頁面渲染須要發送3個請求,在增長配置後,請求數增長到9個。經過並行請求的方式,頁面在發送3個請求時,耗時1000ms,增長到9個請求後,串行耗時爲3400ms,經過併發請求的方式,9個請求耗時下降到440ms。
但在使用async第三方庫請求的過程當中,CPU只能處於等待狀態。爲了充分的利用CPU,咱們採用ECMAScript 6標準的async函數來對此進行改造。
有別於async第三方庫使用回調函數的形式作串行處理,ES6使用await關鍵字等待異步函數返回Promise對象作串行處理。首先咱們基於ES6代碼改寫async第三方庫實現:
圖3 async函數異步使用await關鍵字
而後,咱們能夠在發送請求時,先不使用await關鍵字,僅保存發送請求的Promise對象,在異步請求後端接口過程當中,首先進行頁面初始化的渲染操做,而後再將異步請求的返回結果進行渲染處理,實現以下:
圖4 改進後利用異步請求等待時間作初始化處理
經過這樣的改造,咱們在併發請求多個數據的同時,利用請求的間隙,完成繪製初始化、默認配置計算、時間初始化等工做。充分利用CPU資源,進一步減小js執行耗時340ms。
經過以上優化,整個加載過程累積減小耗時900ms,頁面加載時間由3300ms降至2400ms左右。
智慧機場項目是採用NoahV(運維前端展示層框架,詳情戳這裏)開發的,該框架基於Vue實現,並採用組件化的思路進行頁面元素構建。同時,甘特圖的繪製是經過ECharts進行繪製的。
在甘特圖界面中,用戶須要實時調整時間段,得到對應時間段的航班分配狀況,故在用戶移動時間軸的時候,會根據選擇的時間不斷更新航班的分配狀況,從後端得到對應時間段的航班數據,而後將請求到的數據傳入頁面組件。
基於Vue的雙向數據綁定的特徵,當數據發生變化的時候,Vue會構建監聽對象去監聽數據,再用ECharts重繪甘特圖。以下是組件監聽數據的工做流程。
圖5 組件數據監聽工做流程
從圖5看,當數據傳入的時候,爲了數據和頁面雙向綁定,須要構造監聽對象,構造監聽對象所消耗的時間是根據數據複雜程度決定的。數據越複雜,構造監聽對象所消耗的時間越多。
爲了加快頁面加載速度,咱們在首次加載數據時直接渲染圖形,減小構建監聽對象耗時。在渲染頁面完畢後,延遲構造監聽對象。流程如圖6:
圖6 改造組件數據工做流程
基於這樣的流程優化,航班、機位、待分區航班和待分區機位數據在渲染視圖前減小監聽對象的構建,耗時相應的分別平均減小約230ms、210ms、167ms和151ms,累積減小耗時約800ms。頁面加載耗時由2400ms下降至1600ms。
前面咱們介紹了頁面渲染時減小構建監聽對象的過程加快頁面渲染時間,接下來咱們對可視化渲染視圖部分進行進一步分析。
可視化視圖渲染耗時隨數據量的增長而增大,咱們對視圖渲染流程作進一步的分析,看哪些流程受到數據量影響較大,渲染視圖計算可分爲6個過程,如圖7:
圖7 渲染計算流程
針對上述流程,咱們分別設置不一樣數據量(表一第一列)及單個甘特條包含不一樣圖形數目(表一第二列),而後經過分析工具查看各個階段的耗時狀況,具體如表1:
表1 數據量及每條數據圖形對渲染計算各階段影響
經過表1,咱們能夠分析得出,數據量及每條數據所含圖形數目對於階段一、四、五、6(配置轉換、圖層刷新、圖層渲染和圖層合併)沒有明顯影響。對於階段2(圖層初始化),在只有一個圖形和一條數據時,耗時較短,其餘狀況耗時相差不大;而對於階段3(圖形繪製計算階段),能夠明顯看出,單條數據所包含圖形越多,計算時間越長(表1第五列)。所以咱們在這裏選擇減小繪製圖形數目(相似減小頁面DOM節點)來減小渲染計算的耗時。首先,咱們對甘特條完整圖形進行拆解,如圖8左側甘特條拆解所示:
圖8 甘特條圖形拆分
由圖8所示,A表示發佈狀態、B的顏色表示進港航班狀態、C的顏色表示出港航班狀態,D表示播報狀態,整個條狀圖使用4個圖形繪製。
爲了減小繪製圖形,咱們將這4個圖形合併爲一個圖形。首先,咱們將A、D兩個圖形分別和B、C進行合併,這裏採用設置矩形頂角半徑的方法來繪製弧度,實現如圖9:
圖9 利用頂角弧度替代弧形A、D
而後,咱們利用分段顏色樣式將B、C兩部分合並,實現如圖10:
圖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%。有效的減小了頁面渲染的時間,優化了系統的響應速度,提高了用戶體驗。總體上,性能優化首先是經過性能分析工具來找到性能瓶頸,再針對每項進行優化。大體會從數據請求,資源解析,數據渲染方向作優化,而後再結合選型框架的特徵,進行更細粒度的優化。咱們後續將持續推出相關頁面性能優化文章,各位看官請持續關注AIOps智能運維公衆號~
舒適提示
若是你喜歡本文,請分享到朋友圈,想要得到更多信息,請關注咱們!
若是你有任何問題歡迎留言諮詢~
若是想試用咱們的企業級運維平臺NoahEE,請聯繫郵箱:noah_bd@baidu.com