1. 問題引入
使用vue開發項目,部署后發現web端性能較差,存在內存大量占用。特分析此項目,優化基於vue的web端性能,以提升用戶體驗。
2. 問題分析
2.1 通過查看部署的平台,發現以下幾大現象
1、 首次進入平台,加載緩慢,大概5s空白頁;
2、 切換模塊時,單個模塊加載緩慢;
3、 模塊切換多次后,內存大量占用,導致頁面卡頓或無響應(ie下);

圖1 首次加載

圖2 多次切換
4、 調用OCX控件的頁面在多次切換后,內存無法釋放,比其他模塊響應時間更長;
5、 通過抓包發現,菜單切換多次后,單個接口請求數量會累加;
6、 通過查看代碼,發現有不必要的jq引入,並進行不必要的dom操作;
7、 通過查看代碼,發現echarts並未按需引入;
8、 單個vue文件過大,並未做組件提取、頁面拆分和公共方法提取,大量冗余代碼;
2.2 問題分析
1、 首屏加載慢
打包構建應用時,Javascript 包會變得非常大,影響頁面加載。如果我們能把不同路由對應的組件分割成不同的代碼塊,然后當路由被訪問的時候才加載對應組件,這樣就更加高效了。
2、 切換模塊時,單模塊加載緩慢
l 單個模塊在初始化時調用大量接口,如:需要tab切換才顯示的樹、列表等均在首次加載時調用接口,http連接數並發過多,導致加載緩慢。
l 單個模塊大量接口返回有效數據極少,如平台名稱、端口號等均由不同的接口返回,暫用了http連接,若是合並這部分接口,也可提高響應速度。
3、 模塊切換多次后,內存大量占用
打包構建應用時,未對路由懶加載,所有模塊均打包在一個文件中,Javascript 包會變得非常大,影響頁面加載。
4、 調用OCX控件的頁面在多次切換后,內存無法釋放
Vue-router中切換單入口模塊,由於並未真正切換頁面,調用的OCX控件在每次的實例化中均占用內存,導致內存未釋放。若是可以在OCX控件模塊單獨配置入口,切換過程中可自動釋放內存。
5、 菜單切換多次后,單個接口請求數量會累加
組件之間傳遞數據方式錯誤,且在數據掛載的時候生成實例,導致事件被重復綁定觸發,產生大量並發請求。各瀏覽器對並發的http連接數量有限制,超過數量在ie下http連接會掛起,chrome下也會導致響應緩慢、卡頓。
6、 不必要的jq引入和不必要的dom操作
通過查看代碼,發現項目中引入了jq,僅用於菜單切換時,操作菜單DOM,進行addClass和removeClass操作。在基於vue的項目中需要實現這樣的效果,可直接通過數據驅動,添加三元運算即可。Jq的引入和dom操作沒有必要。
7、 echarts並未按需引入
項目中僅使用地圖(map)、柱狀圖(bar)和折線圖(line),在生產環境引入完整echarts會增加該http請求體積,若是按需引入需要使用的組件,可優化該http連接,減少響應時間。
8、 單個vue文件過大,並未做組件提取、頁面拆分和公共方法提取,大量冗余代碼
通過代碼走查,發現項目中未做共用組件規划、提取。如:tab切換搜索條件,僅改變搜索條件中的一個類型,卻在項目中重復初始化其中的下拉樹等。單個vue文件可達四千行,大量冗余代碼,維護異常困難。
3. 問題總結
通過問題分析,主要有以下方向需要優化:
1、 Vue-router優化
2、 http連接優化
3、 vue- components優化
4、 代碼優化
5、 打包優化
4. 如何優化
4.1 Vue-router優化
4.1.1 路由懶加載
當打包構建應用時,Javascript 包會變得非常大,影響頁面加載。如果我們能把不同路由對應的組件分割成不同的代碼塊,然后當路由被訪問的時候才加載對應組件,這樣就更加高效了。結合 Vue 的異步組件和 Webpack 的代碼分割功能,輕松實現路由組件的懶加載,也可將組件按組分塊。
- 使用const Foo = () => import('./Foo.vue')代替import './Foo.vue';
- 詳見vue-router官網——路由懶加載https://router.vuejs.org/zh-cn/advanced/lazy-loading.html;
4.2 http連接優化
HTTP協議定義Web客戶端如何從服務器請求web頁面,以及服務器如何把web頁面傳送給客戶端,瀏覽器請求獲取數據通過http連接完成,因此,優化http連接優化是web項目優化的重要方向之一。Web項目的由瀏覽器呈現,下面我們來看看瀏覽器對請求的處理過程,如圖3:

圖3 瀏覽器請求處理流程圖
4.2.1 減少HTTP請求
- 合並CSS、js、圖片。將css、js、圖片合並,可以有效減少http請求數;
- 合理規划API,將可合並的接口請求合並。瀏覽器對並發的http請求數量有限制,即使API響應很快,在多個接口並發請求時,仍會在瀏覽器中造成不同程度的卡頓(如ie中部分請求掛起,內存占用變大等);
4.2.2 合理使用緩存
合理設置HTTP緩存。從圖1 瀏覽器請求處理流程圖中可以看出,恰當的緩存設置可以大大減少HTTP請求,節省帶寬。如很少變化的資源(html、css、js、圖片等)通過 HTTP Header中的cache-control和Expires可設定瀏覽器緩存,變化不頻繁又可能變的資源使用Last-Modifed來做請求驗證。
4.2.3 使用字體圖標
建議使用字體圖標代替純色或漸變色的圖標,如使用icomoon。在准備好svg文件后,可通過https://icomoon.io/在線制作字體圖標,需要維護時可導入json文件重新編輯。
使用字體圖標的優點:
- 輕量:一個圖標字體比一系列的圖像(特別是在Retina屏中使用雙倍圖像)要小。一旦圖標字體加載了,圖標就會馬上渲染出來,不需要下載一個圖像。可以減少HTTP請求,還可以配合HTML5離線存儲做性能優化;
- 靈活性:圖標字體可以用過font-size屬性設置其任何大小,還可以加各種文字效果,包括顏色、Hover狀態、透明度、陰影和翻轉等效果。可以在任何背景下顯示。使用位圖的話,必須得為每個不同大小和不同效果的圖像輸出一個不同文件。
- 兼容性:網頁字體支持所有現代瀏覽器,包括IE低版本。
4.2.4 圖片懶加載
在實際的項目開發中,我們通常會遇見這樣的場景:一個頁面有很多圖片,而首屏出現的圖片大概就一兩張,那么我們還要一次性把所有圖片都加載出來嗎?顯然這是愚蠢的,不僅影響頁面渲染速度,還浪費帶寬。這也就是們通常所說的首屏加載,技術上現實其中要用的技術就是圖片懶加載--到可視區域再加載。
4.3 組件優化
現大部分業務或管理系統中,模塊較多、單模塊功能較多的情況時有發生,若是組件沒有划分好,會導致頁面加載緩慢,影響用戶體驗和使用。針對此情況,可將模塊內按照布局或功能重新划分vue組件:
- 按模塊划分路由。按照業務模塊划分路由及子路由,保證模塊間的隔離;
- 模塊內按布局或功能划分組件。單個模塊功能較多或邏輯較復雜時,按照布局划分為左右或上下及其組合模式划分組件,以子組件的方式放在模塊中,方便打包優化、復用、功能拓展及維護;
- 能復用的組件盡量復用。布局、功能模塊等均可復用,如:tab中的篩選條件、詳情彈窗、表單等。
4.4 代碼優化
4.4.1 第三方引入優化
- 去除不必要的引入,如jq;
- 按需引入echarts包;
4.4.2 基礎優化
- Vue官網中的規范需要遵循,在此不再贅述https://cn.vuejs.org/v2/guide/;
- v-if,v-show的選擇。權限相關使用v-if、頻繁切換使用v-show、不頻繁切換使用v-if;
- style中使用<style scoped>避免沖突;
- 全局style盡量抽象,提高復用率,減小css文件大小,節省帶寬;
- 提取共用的方法,放在util.js中,例如表單校驗的封裝;
4.5 打包優化
若打包出的vender.js和app.js較大,在瀏覽器調試窗口可看到這兩個文件加載和解析時間需要幾秒鍾。App.js可通過組件懶加載解決,vender包該如何解決?
解決方案:打包wender時不打包vue、vuex、vue-router、axios等,換為直接引入(需要在webpack中配置不需要打包的庫)。
5. 總結
Web項目中關於性能的優化有很多的開發細節需要注意,如js、css、vue等開發規范均需注意。以上為我對web項目(vue項目)性能優化的思考,那么,在項目進行的各個階段,如何避免性能差的問題?如何找到影響項目性能的原因呢?
5.1 項目構建前
- 根據交互稿或視覺稿,合理划分pages,一般按照模塊和子模塊划分;
- 使用路由懶加載,實現模塊化與按需加載的效果,優化首屏性能;
- 提取公共組件,盡量與業務隔離,如篩選條件等;
- 提取公共方法,放在util.js中,如表單校驗封裝;
- 提取在項目中出現較多的功能模塊,如彈窗詳情等;
- 與后台開發人員定義接口協議,模塊中能合並的盡量合並。
5.2 項目構建中和完成后
- 開啟eslint驗證,看到錯誤和警告信息及時解決;
- 打開瀏覽器調試窗口,查看Network中從發起網頁頁面請求Request后分析HTTP請求后得到的各個請求資源信息(包括狀態、資源類型、大小、所用時間等),可以根據這個進行網絡性能優化。如查看哪些http請求返回資源非常大或耗用時間較長,可針對處理;
- 打開瀏覽器調試窗口,在Timeline中記錄並分析在網站的生命周期內所發生的各類事件,以此可以提高網頁的運行時間的性能;
- 代碼編寫過程中不斷思考是否可優化模塊或做共性組件提取;
- 及時代碼審核,提高代碼質量;
