Vue常用效能優化
Vue
常用的一些優化方式,主要是在構建專案過程需要注意的方面。
編碼優化
避免響應所有資料
不要將所有的資料都放到data
中,data
中的資料都會增加getter
和setter
,並且會收集watcher
,這樣還佔記憶體,不需要響應式的資料我們可以直接定義在例項上。
<template>
<view>
</view>
</template>
<script>
export default {
components: {},
data: () => ({
}),
beforeCreate: function(){
this.timer = null;
}
}
</script>
<style scoped>
</style>
函式式元件
函式組是一個不包含狀態和例項的元件,簡單的說,就是元件不支援響應式,並且不能通過this
關鍵字引用自己。因為函式式元件沒有狀態,所以它們不需要像Vue
的響應式系統一樣需要經過額外的初始化,這樣就可以避免相關操作帶來的效能消耗。當然函式式元件仍然會對相應的變化做出響應式改變,比如新傳入新的props
,但是在元件本身中,它無法知道資料何時發生了更改,因為它不維護自己的狀態。很多場景非常適合使用函式式元件:
- 一個簡單的展示元件,也就是所謂的
dumb
元件。例如buttons
、pills
、tags
、cards
等,甚至整個頁面都是靜態文字,比如About
頁面。 - 高階元件,即用於接收一個元件作為引數,返回一個被包裝過的元件。
v-for
迴圈中的每項通常都是很好的候選項。
區分computed和watch使用場景
computed
是計算屬性,依賴其它屬性值,並且computed
的值有快取,只有它依賴的屬性值發生改變,下一次獲取computed
的值時才會重新計算computed
的值。
watch
更多的是觀察的作用,類似於某些資料的監聽回撥,每當監聽的資料變化時都會執行回撥進行後續操作。
當我們需要進行數值計算,並且依賴於其它資料時,應該使用computed
,因為可以利用computed
的快取特性,避免每次獲取值時,都要重新計算。當我們需要在資料變化時執行非同步或開銷較大的操作時,應該使用watch
,使用watch
選項允許我們執行非同步操作,限制我們執行該操作的頻率,並在我們得到最終結果前,設定中間狀態。
v-for新增key且避免同時使用v-if
v-for
遍歷必須為item
新增key
,且儘量不要使用index
而要使用唯一id
去標識item
,在列表資料進行遍歷渲染時,設定唯一key
值方便Vue.js
內部機制精準找到該條列表資料,當state
更新時,新的狀態值和舊的狀態值對比,較快地定位到diff
。v-for
遍歷避免同時使用v-if
,v-for
比v-if
優先順序高,如果每一次都需要遍歷整個陣列,將會影響速度。
區分v-if與v-show使用場景
- 實現方式:
v-if
是動態的向DOM
樹內新增或者刪除DOM
元素,v-show
是通過設定DOM
元素的display
樣式屬性控制顯隱。 - 編譯過程:
v-if
切換有一個區域性編譯解除安裝的過程,切換過程中合適地銷燬和重建內部的事件監聽和子元件,v-show
只是簡單的基於CSS
切換。 - 編譯條件:
v-if
是惰性的,如果初始條件為假,則什麼也不做,只有在條件第一次變為真時才開始區域性編譯,v-show
是在任何條件下都被編譯,然後被快取,而且DOM
元素保留。 - 效能消耗:
v-if
有更高的切換消耗,v-show
有更高的初始渲染消耗。 - 使用場景:
v-if
適合條件不太可能改變的情況,v-show
適合條件頻繁切換的情況。
長列表效能優化
Vue
會通過Object.defineProperty
對資料進行劫持,來實現檢視響應資料的變化,然而有些時候我們的元件就是純粹的資料展示,不會有任何改變,我們就不需要Vue
來劫持我們的資料,在大量資料展示的情況下,這能夠很明顯的減少元件初始化的時間,可以通過Object.freeze
方法來凍結一個物件,一旦被凍結的物件就再也不能被修改了。對於需要修改的長列表的優化大列表兩個核心,一個分段一個區分,具體執行分為:僅渲染視窗可見的資料、進行函式節流、 減少駐留的VNode
和Vue
元件,不使用顯示的子元件slot
方式,改為手動建立虛擬DOM
來切斷物件引用。
export default {
data: () => ({
users: {}
}),
async created() {
const users = await axios.get("/api/users");
this.users = Object.freeze(users);
}
};
路由懶載入
Vue
是單頁面應用,可能會有很多的路由引入,這樣使用webpcak
打包後的檔案很大,當進入首頁時,載入的資源過多,頁面會出現白屏的情況,不利於使用者體驗。如果我們能把不同路由對應的元件分割成不同的程式碼塊,然後當路由被訪問的時候才載入對應的元件,這樣就更加高效。對於Vue
路由懶載入的方式有Vue
非同步元件、動態import
、webpack
提供的require.ensure
,最常用的就是動態import
的方式。
{
path: "/example",
name: "example",
//打包後,每個元件單獨生成一個chunk檔案
component: () => import("@/views/example.vue")
}
服務端渲染SSR
如果需要優化首屏載入速度並且首屏載入速度是至關重要的點,那麼就需要服務端渲染SSR
,服務端渲染SSR
其實是優缺點並行的,需要合理決定是否真的需要服務端渲染。
優點
- 更好的
SEO
,由於搜尋引擎爬蟲抓取工具可以直接檢視完全渲染的頁面,如果SEO
對站點至關重要,而頁面又是非同步獲取內容,則可能需要伺服器端渲染SSR
解決此問題。 - 更快的內容到達時間
time-to-content
,特別是對於緩慢的網路情況或執行緩慢的裝置,無需等待所有的JavaScript
都完成下載並執行,使用者將會更快速地看到完整渲染的頁面,通常可以產生更好的使用者體驗,並且對於那些內容到達時間time-to-content
與轉化率直接相關的應用程式而言,伺服器端渲染SSR
至關重要。
缺點
- 開發條件所限,瀏覽器特定的程式碼,只能在某些生命週期鉤子函式
lifecycle hook
中使用,一些外部擴充套件庫external library
可能需要特殊處理,才能在伺服器渲染應用程式中執行。 - 涉及構建設定和部署的更多要求,與可以部署在任何靜態檔案伺服器上的完全靜態單頁面應用程式
SPA
不同,伺服器渲染應用程式,通常需要處於Node.js server
執行環境。 - 更大的伺服器端負載,在
Node.js
中渲染完整的應用程式,顯然會比僅僅提供靜態檔案的server
更加大量佔用CPU
資源CPU-intensive
-CPU
密集型,因此如果預料在高流量環境high traffic
下使用,需要準備相應的伺服器負載,並明智地採用快取策略。
使用keep-alive元件
當在元件之間切換的時候,有時會想保持這些元件的狀態,以避免反覆重渲染導致的效能等問題,使用<keep-alive>
包裹動態元件時,會快取不活動的元件例項,而不是銷燬它們。重新建立動態元件的行為通常是非常有用的,但是在有些情況下我們更希望那些標籤的元件例項能夠被在它們第一次被建立的時候快取下來,此時使用<keep-alive>
包裹元件即可快取當前元件例項,將元件快取到記憶體,用於保留元件狀態或避免重新渲染,和<transition>
相似它,其自身不會渲染一個DOM
元素,也不會出現在元件的父元件鏈中。
<keep-alive>
<component v-bind:is="currentComponent" class="tab"></component>
</keep-alive>
打包優化
模板預編譯
當使用DOM
內模板或JavaScript
內的字串模板時,模板會在執行時被編譯為渲染函式,通常情況下這個過程已經足夠快了,但對效能敏感的應用還是最好避免這種用法。預編譯模板最簡單的方式就是使用單檔案元件——相關的構建設定會自動把預編譯處理好,所以構建好的程式碼已經包含了編譯出來的渲染函式而不是原始的模板字串。如果使用webpack
,並且喜歡分離JavaScript
和模板檔案,可以使用vue-template-loader
,其可以在構建過程中把模板檔案轉換成為JavaScript
渲染函式。
SourceMap
在專案進行打包後,會將開發中的多個檔案程式碼打包到一個檔案中,並且經過壓縮、去掉多餘的空格、babel
編譯化後,最終將編譯得到的程式碼會用於線上環境,那麼這樣處理後的程式碼和原始碼會有很大的差別,當有bug
的時候,我們只能定位到壓縮處理後的程式碼位置,無法定位到開發環境中的程式碼,對於開發來說不好調式定位問題,因此sourceMap
出現了,它就是為了解決不好調式程式碼問題的,線上上環境則需要關閉sourceMap
。
配置splitChunksPlugins
Webpack
內建了專門用於提取多個Chunk
中的公共部分的外掛CommonsChunkPlugin
,是用於提取公共程式碼的工具,CommonsChunkPlugin
於4.0
及以後被移除,使用SplitChunksPlugin
替代。
使用treeShaking
tree shaking
是一個術語,通常用於描述移除JavaScript
上下文中的未引用程式碼dead-code
,其依賴於ES2015
模組系統中的靜態結構特性,例如import
和export
,這個術語和概念實際上是興起於ES2015
模組打包工具rollup
。
第三方外掛的按需引入
我們在專案中經常會需要引入第三方外掛,如果我們直接引入整個外掛,會導致專案的體積太大,我們可以藉助babel-plugin-component
,然後可以只引入需要的元件,以達到減小專案體積的目的,以專案中引入element-ui
元件庫為例。
{
"presets": [["es2015", { "modules": false }]],
"plugins": [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}
import Vue from 'vue';
import { Button, Select } from 'element-ui';
Vue.use(Button)
Vue.use(Select)
每日一題
https://github.com/WindrunnerMax/EveryDay
參考
https://zhuanlan.zhihu.com/p/121000054
https://www.jianshu.com/p/f372d0e3de80
https://juejin.im/post/6844903887787278349
https://juejin.im/post/6844904189999448071
https://www.lagou.com/lgeduarticle/22278.html
https://www.cnblogs.com/mmzuo-798/p/11778044.html
https://blog.csdn.net/gtlbtnq9mr3/article/details/104889927