vue項目性能優化(彙總)

Vue 框架通過數據雙向綁定和虛擬 DOM 技術,幫我們處理了前端開發中最髒最累的 DOM 操作部分, 我們不再需要去考慮如何操作 DOM 以及如何最高效地操作 DOM;但 Vue 項目中仍然存在項目首屏優化、Webpack 編譯配置優化等問題,所以我們仍然需要去關注 Vue 項目性能方面的優化,使項目具有更高效的性能、更好的用戶體驗。

一、基礎優化(代碼以及編碼規範)

1、v-if 和 v-show 區分使用場景

v-if不渲染DOM,v-show會預渲染DOM,注意區分使用

2、computed 和 watch 區分使用場景

computed:是計算屬性,依賴其它屬性值,並且 computed 的值有緩存,只有它依賴的屬性值發生改變,下一次獲取 computed 的值時纔會重新計算 computed 的值;

watch:更多的是「觀察」的作用,類似於某些數據的監聽回調 ,每當監聽的數據變化時都會執行回調進行後續操作

運用場景:

當我們需要進行數值計算,並且依賴於其它數據時,應該使用 computed,因爲可以利用 computed 的緩存特性,避免每次獲取值時,都要重新計算;

當我們需要在數據變化時執行異步或開銷較大的操作時,應該使用 watch,使用 watch 選項允許我們執行異步操作 ( 訪問一個 API ),限制我們執行該操作的頻率,並在我們得到最終結果前,設置中間狀態。這些都是計算屬性無法做到的。

3、v-for 遍歷必須爲 item 添加 key,且避免同時使用 v-if

在列表數據進行遍歷渲染時,需要爲每一項 item 設置唯一 key 值,方便 Vue.js 內部機制精準找到該條列表數據。當 state 更新時,新的狀態值和舊的狀態值對比,較快地定位到 diff 。

v-for 比 v-if 優先級高,如果每一次都需要遍歷整個數組,將會影響速度,尤其是當之需要渲染很小一部分的時候,必要情況下應該替換成 computed 屬性。

4、事件及銷燬

Vue組件銷燬時,會自動清理它與其它實例的連接,解綁它的全部指令及事件監聽器,但是僅限於組件本身的事件。
也就是說,在js內使用addEventListener等方式是不會自動銷燬的,我們需要在組件銷燬時手動移除這些事件的監聽,以免造成內存泄露

created() {
 addEventListener('touchmove', this.touchmove, false)
},
beforeDestroy() {
 removeEventListener('touchmove', this.touchmove, false)
}
5、長列表以及不需要數據劫持的場景

Vue 會通過 Object.defineProperty 對數據進行劫持,來實現視圖響應數據的變化,然而有些時候我們的組件就是純粹的數據展示,不會有任何改變,我們就不需要 Vue 來劫持我們的數據,在大量數據展示的情況下,這能夠很明顯的減少組件初始化的時間,那如何禁止 Vue 劫持我們的數據呢?可以通過 Object.freeze() (凍結) 方法來凍結一個對象,一旦被凍結的對象就再也不能被修改了。或者可以用 Object.seal() (密封),具體區別自己去查吧

二、組件優化(加載方式)

vue 的組件化深受大家喜愛,到底組件拆到什麼程度算是合理,還要因項目大小而異,小型項目可以簡單幾個組件搞定,甚至不用 vuex,axios 等等,如果規模較大就要細分組件,越細越好,包括佈局的封裝,按鈕,表單,提示框,輪播等,推薦看下 Element 組件庫的代碼,沒時間寫這麼詳細可以直接用 Element 庫,分幾點進行優化

組件有明確含義,只處理類似的業務。複用性越高越好,配置性越強越好。
自己封裝組件還是遵循配置 props 細化的規則。
組件分類,我習慣性的按照三類劃分,page、page-item 和 layout,page 是路由控制的部分,page-item 屬於 page 裏各個佈局塊如 banner、side 等等,layout 裏放置多個頁面至少出現兩次的組件,如 icon, scrollTop 等

1、路由懶加載
const Foo =()=>import('./Foo.vue')
const Aoo =()=>import(/* webpackChunkName: "ab90fb63-90a8" */'./Aoo.vue')
constrouter =newVueRouter({
	routes: [{
		path:'/foo',
		component: Foo 
	},{
		path:'/aoo',
		component: Aoo 
	}]
})         

webpackChunkName
有時候我們想把某個路由下的所有組件都打包在同個異步塊 (chunk) 中。只需要使用 命名 chunk,一個特殊的註釋語法來提供 chunk name (需要 Webpack > 2.4)。

2、異步組件
// template
<test v-if="showTest"></test>
// script
  components: {
    test: () => import('./test') // 將組件異步引入,告訴webpack,將該部分代碼分割打包
  },
  methods:{
      clickTest () {
          this.showTest = !this.showTest
    }
  }
3、圖片資源懶加載

到滾動到可視區域後再去加載, vue-lazyload

4、第三方庫按需引入

我們在項目中經常會需要引入第三方插件,如果我們直接引入整個插件,會導致項目的體積太大,我們可以藉助babel-plugin-component,然後可以只引入需要的組件,以達到減小項目體積的目的。以下爲項目中引入 element-ui 組件庫爲例:

  1. 安裝 babel-plugin-component:
    npm install babel-plugin-component -D

  2. 將 .babelrc 修改爲:

{
  "presets": [["es2015", { "modules": false }]],
  "plugins": [
    [
      "component",
      {
        "libraryName": "element-ui",
        "styleLibraryName": "theme-chalk"
      }
    ]
  ]
}
// 使用
import { Dialog, Loading } from 'element-ui'
Vue.use(Dialog)

看一下Echarts吧,這個對於數據分析也常用:
首先安裝babel-plugin-equire : npm i babel-plugin-equire -D
然後,在.babelrc文件中添加該插件

{
  "plugins": [
       // other plugins
       ...
    "equire"
  ]
}

創建一個js

// echarts.js
// eslint-disable-next-line
const echarts = equire([
  'tooltip',
  'candlestick',
  'bar',
  'line',
  'axisPointer',
  'legend',
  'grid'
])
export default echarts

// 業務組件,引入echarts
import echarts from '@/assets/lib/echarts'
// 使用與以前一樣

按需加載echarts
解決vue-cli首屏加載慢的問題

5、CDN加速

在index.html中引入cdn資源

...
<body>

<div id="app">
</div>
<!-- built files will be auto injected -->
<script src="https://cdn.bootcss.com/vue/2.5.2/vue.min.js"></script>
<script src="https://cdn.bootcss.com/vue-router/3.0.1/vue-router.min.js"></script>
<script src="https://cdn.bootcss.com/vuex/3.0.1/vuex.min.js"></script>
<script src="https://cdn.bootcss.com/vue-resource/1.5.1/vue-resource.min.js"></script>
</body>
...

修改 build/webpack.base.conf.js

module.exports = {
context: path.resolve(__dirname, '../'),
entry: {
app: './src/main.js'
},
externals:{
'vue': 'Vue',
'vue-router': 'VueRouter',
'vuex':'Vuex',
'vue-resource': 'VueResource'
},
...
}

修改src/main.js src/router/index.js 註釋掉import引入的vue,vue-resource

// import Vue from 'vue'
// import VueResource from 'vue-resource'
// Vue.use(VueResource)

vue-cli3.0 的話
vue.config.js

module.exports = {
    baseUrl: process.env.NODE_ENV === "production" ? "./" : "/",
    outputDir: process.env.outputDir,
    configureWebpack: {
        externals: {
            vue: "Vue",
            vuex: "Vuex",
            "vue-router": "VueRouter",
            "element-ui": "ELEMENT"
        }
    }
};
6、服務端渲染 SSR or 預渲染

服務端渲染是指 Vue 在客戶端將標籤渲染成的整個 html 片段的工作在服務端完成,服務端形成的 html 片段直接返回給客戶端這個過程就叫做服務端渲染。
更好的 SEO: 因爲 SPA 頁面的內容是通過 Ajax 獲取,而搜索引擎爬取工具並不會等待 Ajax 異步完成後再抓取頁面內容,所以在 SPA 中是抓取不到頁面通過 Ajax 獲取到的內容;而 SSR 是直接由服務端返回已經渲染好的頁面(數據已經包含在頁面中),所以搜索引擎爬取工具可以抓取渲染好的頁面;

更快的內容到達時間(首屏加載更快): SPA 會等待所有 Vue 編譯後的 js 文件都下載完成後,纔開始進行頁面的渲染,文件下載等需要一定的時間等,所以首屏渲染需要一定的時間;SSR 直接由服務端渲染好頁面直接返回顯示,無需等待下載 js 文件及再去渲染等,所以 SSR 有更快的內容到達時間;

(2)服務端渲染的缺點:

更多的開發條件限制: 例如服務端渲染只支持 beforCreate 和 created 兩個鉤子函數,這會導致一些外部擴展庫需要特殊處理,才能在服務端渲染應用程序中運行;並且與可以部署在任何靜態文件服務器上的完全靜態單頁面應用程序 SPA 不同,服務端渲染應用程序,需要處於 Node.js server 運行環境;

更多的服務器負載:在 Node.js 中渲染完整的應用程序,顯然會比僅僅提供靜態文件的 server 更加大量佔用CPU 資源,因此如果你預料在高流量環境下使用,請準備相應的服務器負載,並明智地採用緩存策略。

二、配置優化(webpack)

使用webpack-bundle-analyzer 分析打包後的生成的文件結構進行優化
安裝完
在package.json配置 “analyz”: “NODE_ENV=production npm_config_report=true npm run build” ,然後運行 npm run analyz 即可,通過分析來具體優化具體內容
在這裏插入圖片描述

1、屏蔽sourceMap

productionSourceMap: false,

2、啓用 gzip壓縮

安裝 compression-webpack-plugin
npm install compression-webpack-plugin --save-dev,
這裏有個坑,就是如果你的vue版本爲2.5.2 及以下 webpack版本爲3.6.0及以下時,建議安裝compression-webpack-plugin的版本爲1.0.0-beta.1 而不是2.0.0,否則可能打包時會報

ValidationError: Compression Plugin Invalid Options
options should NOT have additional properties

將vue項目中的 config/index.js中productionGzip: false改爲 productionGzip: true;

	productionGzip: true,
	productionGzipExtensions: ['js', 'css'],

最後服務端也要開啓Gzip,具體服務器具體操作,可以看一下:關於Gzip壓縮

3、樣式的抽離與合併

CommonsChunkPlugin:

        new webpack.optimize.CommonsChunkPlugin({
            name: 'vendor',
            filename: '[name].js'
        }),

查看dist目錄下,新增了一個vendor.js的文件

new webpack.optimize.CommonsChunkPlugin({
            name: 'app',
            async: 'vendor-async',
            children: true,
            minChunks: 3, // 最小混合文件數
        }),

extract-text-webpack-plugin:
樣式文件分開打包

new ExtractTextPlugin({
            filename: utils.assetsPath('css/[name].css'),
            allChunks: false, // 不打包到一起
        }),
4、瀏覽器緩存

爲了提高用戶加載頁面的速度,對靜態資源進行緩存是非常必要的,根據是否需要重新向服務器發起請求來分類,將 HTTP 緩存規則分爲兩大類(強制緩存,對比緩存),如果對緩存機制還不是瞭解很清楚的,可以參考作者寫的關於 HTTP 緩存的文章《深入理解HTTP緩存機制及原理》,這裏不再贅述。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章