uni-app 性能優化建議
1. 前言
初期學習開發 uni-app 項目,我們一般不會在意項目的性能問題,項目功能較少或者數據較少的時候,不會對項目性能的重要性有很大的感受。
但如果開發大型項目,或者數據量比較大的時候,項目性能的問題就顯得尤為重要。一種需求的不同實現方式,頁面的加載速度會差幾倍甚至上百倍。
所以我們在開發項目之前,最好先了解一下項目性能優化的幾種方式,在項目初期就打好基礎,以免后期維護過于麻煩。
這節課我們主要講解一些性能優化的小建議,在項目開發之前最好看一看,知道開發的重點需要注意哪些地方。
2. uni-app 運行原理
uni-app 項目的視圖層和邏輯層是分離開的,雖然我們在開發項目過程中,將 html、js 代碼都寫在同一個文件中,但是實際運行的時候是分離開的。
視圖層負責進行頁面渲染,也就是用戶能看到的頁面,用來展示數據的,包括頁面結構代碼 <template>
部分、頁面樣式代碼 <style>
部分。
邏輯層負責執行后端的業務邏輯,用戶看不到這部分的邏輯,用來處理數據的,包括頁面邏輯代碼 <script>
部分,以及其他 .js 文件。
視圖層和邏輯層分離,減少了項目的耦合程度,并且邏輯層的運算不會影響到視圖層的渲染,窗體動畫會比較穩。而兩層分離也有一個缺點,就是這兩層互相通信會有損耗。
我們下面進行的性能優化,都是基于uni-app 運行原理來操作的,下面來具體看一下。
3. 性能優化建議
3.1 長列表優化
我們開發項目時,我們經常會循環長列表,將長列表中的數據逐一展示在項目中,但是你開發過程中,有沒有出現過一旦數據過多項目加載會變得很慢的問題呢?
長列表的應用有許多需要我們注意的地方,或許你在開發過程中沒有注意下面幾個問題造成長列表加載過慢,我們來具體看看。
3.1.1 長列表差量數據更新
如果你長列表的數據中,每個列表都有可能差量更新,則需要將長列表中的每個 item 都做成一個組件。不然其中每個 item 更新,都會造成整個長列表的重新加載,嚴重良妃系統資源,我們來舉個例子。
比如我們加載博文的100條評論,每條評論都有一個點贊功能。
如果每條評論沒有做成單獨的組件,用戶每次給其中一條評論點贊一次,系統都會重新加載這100條評論。
如果每條評論都做成了單獨的組件,用戶給其中一條評論點贊,系統只會重新加載點贊的這一條評論,其他評論不受影響,合理利用系統資源。
實例:
<template>
<view>
<view class="thumb" v-for="item in testdata">
<view>{{item}}</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
testdata: ["評價1","評價2","評價3","評價4","評價5"]
}
}
}
</script>
<style>
.thumb{
text-align: center;
margin-top: 20px;
}
</style>
// thumbitem.vue 將每個 item 包裝成組件
<template>
<view>
<!-- 顯示 item 信息 -->
<view>{{item}}</view>
<!-- 點贊按鈕,點擊觸發 thumb 方法 -->
<button @click="thumb(index)">點贊數:{{thumbs}}</button>
</view>
</template>
<script>
export default {
props:['item'],
data() {
return {
thumbs:0
};
},
methods: {
// 每次觸發 thumb 方法,點贊數 thumbs 變量就加 1
thumb(){
this.thumbs += 1
}
}
}
</script>
3.1.2 長列表無差量數據更新
如果長列表中,每個 item 不會單獨去更新,那我們就沒有必要去將每個 item 都做成一個組件了,直接循環長列表顯示 item 就可以。
實例:
// index.vue 循環加載長列表
<template>
<view>
<view class="thumb" v-for="item in testdata">
<ThumbItem :item='item'></ThumbItem>
</view>
</view>
</template>
<script>
Import ThumbItem from "components/thumbitem/thumbitem.vue"
export default {
components: {
ThumbItem
},
data() {
return {
testdata: ["評價1","評價2","評價3","評價4","評價5"]
}
}
}
</script>
<style>
.thumb{
text-align: center;
margin-top: 20px;
}
</style>
我們在開發過程中,不需要每次都將長列表的 item 包裝成組件,每個 item 需要差量數據更新的時候,才需要包裝成組件。
組件在頁面初始化時會占用更多的內存,并且遍歷節點也會更慢,每個組件渲染時都會觸發一次通信,太多組件就會阻塞通信。所以我們要將好刀用在刀刃上,不分情況到處使用反而會適得其反。深層節點的嵌套也是同樣的道理,我們開發的時候要注意盡量避免深層節點嵌套。
在實際項目開發中,長列表一般是由邏輯層處理后返回的,數據是變化的,如果長列表中的數據需要展示在頁面上,那么我們就將長列表定義在 data 中,如果變量不需要展示在視圖中,我們盡量將變量定于在 data 外部。
因為data 中的數據每次發生變化,視圖層都要重新渲染頁面。這樣做可以盡量避免資源的浪費,這條建議同樣也適用于其他變量。
3.2 減少一次性加載的節點數量
頁面初始化時,邏輯層如果一次性向視圖層傳遞很多數據,不僅會造成邏輯層和視圖層之間的通訊變化,由于視圖層一次渲染的數據過多,還會造成頁面的卡頓。
所以如果數據過多,建議進行分頁加載。比如:服務端要返回1000條數據,可以一次加載100條,500ms 后再進行下一次加載。
3.3 盡量避免兩層頻繁通信
上面我們提到過,邏輯層與視圖層分離會造成一個缺點,就是兩層之間通訊的損耗,如果兩層之間頻繁通信,可能會造成通訊阻塞,影響項目的正常運行,如果盡量避免兩層之間的頻繁通信呢?主要有以下幾點:
3.3.1 scroll-view 組件的使用
- 使用scroll-view 組件時,要盡量減少監聽滾動事件,因為在監聽 scroll-view 的滾動事件時,視圖層會頻繁的向邏輯層發送數據;
- 不要實時的改變 scroll-top、scroll-left 屬性,可能造成通訊卡頓;
- 如果要實現下拉刷新的功能,建議使用頁面的滾動,而不是 scroll-view;
- 不要在 scroll-view 組件中放長列表,會導致性能問題。
3.3.2 圖片、動畫加載問題
- 盡量使用壓縮圖片;
- 盡量使用css 動畫,而不是通過 js 的定時器操作界面做動畫;
- 如果項目中不可避免的需要加載大量的動畫和圖片,建議加載時進行延時處理,分批進行大量數據通訊,提高頁面的流暢性。否則會造成頁面切換卡頓、掉幀等問題;
- App-nvue 和 H5 項目總,還支持頁面預載,使用API uni.preloadPage,開發時可以使用提高用戶的操作體驗。
3.4 使用nvue代替vue
因為 nvue 頁面開發限制比較多,我們前面建議大家盡量不要使用 nvue 來開發項目,但是如果更加看重項目性能問題,可以使用nvue 來代替 vue。
因為 nvue 是基于 weex 的原生渲染,可以有效提高頁面的流暢程度。
如果對項目啟動速度有更高的要求,如果項目支持的話,甚至可以將項目設置為純 nvue 項目,這樣整個應用都使用原生渲染,不加載 webview 框架,這樣項目的啟動速度會更快。
4. 小結
性能優化問題,在項目開發過程中,會變得越來越重要,最好在開發之前就了解各種優化性能的小技巧,這樣后期開發也會更加得心應手一些。
本小節可以先瀏覽一遍項目開發中性能優化的這幾個建議,大體記得哪些方面需要注意。等項目用到的時候,再來結合課程應用到實際項目中,這樣也會理解的更加深刻。