您好,登錄后才能下訂單哦!
這篇文章主要介紹了mpvue如何優化性能,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
先上個優化前后的圖:
可以看到打包后的代碼量從813KB
減少到387KB
,Audits體驗評分從B
到A
,效果還是比較明顯的。其實這個指標說明不了什么,而且輕易就可以做到,更重要的是優化小程序運行過程中的卡頓感,請耐心往下看。
常規優化
常規的Web端優化方法在小程序中也是適用的,而且不可忽視。
一、壓縮圖片
這一步最簡單,但是容易被忽視。在tiny上在線壓縮,然后下載替換即可。
我這項目的壓縮率高達72%
,可以說打包后的代碼從813KB
降到387KB
大部分都是歸功于壓縮圖片了。
二、移除無用的庫
我之前在項目中使用了Vant Weapp,在static
目錄下引入了整個庫,但實際上我只使用了button
,field
,dialog
等幾個組件,實在是沒必要。
所以干脆移除掉了,微信小程序自身提供的button
,wx.showModal
等一些組件基本可以滿足需求,自己手寫一下樣式也不用花什么時間。
在這里建議大家,在微信小程序中,盡量避免使用過多的依賴庫。
不要貪圖方便而引入一些比較大的庫,小程序不同于Web
,限制比較多,能自己寫一下就盡量自己寫一下吧。
小程序的優化
咱們首先得看一下官方優化建議,大多是圍繞這個建議去做。
一、開啟Vue.config._mpTrace = true
這個是mpvue
性能優化的一個黑科技啊,可能大多數同學都不知道這個,我在官方文檔都沒有搜到到這個配置,我真的是服了。我能找到這個配置也是Google機緣巧合下看到的,出處:mpvue重要更新,頁面更新機制進行全面升級
具體做法是在/src/main.js
添加Vue.config._mpTrace = true
,如:
Vue.config._mpTrace = true Vue.config.productionTip = false App.mpType = 'app'
添加了Vue.config._mpTrace
屬性,這樣就可以看到console里會打印每500ms更新的數據量。如圖:
如果數據更新量很大,會明顯感覺小程序運行卡頓,反之就流暢。因此我們可以根據這個指標,逐步找出性能瓶頸并解決掉。
二、精簡data
1. 過濾api返回的冗余數據
后端的api可能是需要同時為iOS,Android,H5等提供服務的,往往會有些冗余的數據小程序是用不到的。比如api返回的一個文章列表
數據有很多字段:
this.articleList = [ { articleId: 1, desc: 'xxxxxx', author: 'fengxianqi', time: 'xxx', comments: [ { userId: 2, conent: 'xxx' } ] }, { articleId: 2 // ... }, // ... ]
假設我們在小程序中只需要用到列表中的部分字段,如果不對數據做處理,將整個articleList
都setData
進去,是不明智的。
小程序官方文檔:單次設置的數據不能超過1024kB,請盡量避免一次設置過多的數據。
可以看出,內存是很寶貴的,當articleList
數據量非常大超過1M時,某些機型就會爆掉(我在iOS中遇到過很多次)。
因此,需要將接口返回的數據剔除掉不需要的,再setData
,回到我們上面的articleList
例子,假設我們只需要用articleId
和author
這兩個字段,可以這樣:
import { getArticleList } from '@/api/article' export default { data () { return { articleList: [] } } methods: { getList () { getArticleList().then(res => { let rawList = res.list this.articleList = this.simplifyArticleList(rawList) }) }, simplifyArticleList (list) { return list.map(item => { return { articleId: item.articleId, author: item.author // 需要哪些字段就加上哪些字段 } }) } } }
這里我們將返回的數據通過simplifyArticleList
來精簡數據,此時過濾后的articleList
中的數據類似:
[ {articleId: 1, author: 'fengxianqi'}, {articleId: 2, author: 'others'} // ... ]
當然,如果你的需求中是所有數據都要用到(或者大部分數據),就沒必要做一層精簡了,收益不大。畢竟精簡數據的函數中具體的字段,是會增加維護成本的。
PS: 在我個人的實際操作中,做數據過濾雖然增加了維護的成本,但一般收益都很大,因次這個方法比較推薦。
2. data()中只放需要的數據
import xx from 'xx.js' export default { data () { return { xx, otherXX: '2' } } }
有些同學可能會習慣將import
的東西都先放進data
中,再在methods
中使用,在小程序中可能是個不好的習慣。
因為通過Vue.config._mpTrace = true
在更新某個數據時,我對比放進data和不放進data中的兩種情況會有差別。
所以我猜測可能是data是會一起更新的,比如只是想更新otherXX
時,會同時將xx
也一起合起來setData
了。
3. 靜態圖片放進static
這個問題和上面的問題其實是一樣的,有時候我們會通過import
的方式引入,比如這樣:
<template> <img :src="UserIcon"> </template> <script> import UserIcon from '@/assets/images/user_icon.png' export default { data () { return { UserIcon } } } </script>
這樣會導致打包后的代碼,圖片是base64
形式(很長的一段字符串)存放在data
中,不利于精簡data。同時當該組件多個地方使用時,每個組件實例都會攜帶這一段很長的base64
代碼,進一步導致數據的冗余。
因此,建議將靜態圖片放到static
目錄下,這樣引用:
<template> <img src="/static/images/user_icon.png"> </template>
代碼也更簡潔清爽。
看一下做了上面操作的前后對比圖,使用體驗上也流暢了很多。
三、swiper優化
小程序自身提供的swiper
組件性能上不是很好,使用時要注意。參考著兩個思路:
【優化】解決swiper渲染很多圖片時的卡頓
想請教一下小程序swiper組件的問題
在我使用時,由于需求原因,動態刪掉swiper-item的思路不可行(手滑時會造成抖動)。因此只能作罷。但仍然可以優化一下:
將未顯示的swiper-item
中的圖片用v-if
隱藏到,當判斷到current時才顯示,防止大量圖片的渲染導致的性能問題。
四、vuex使用注意事項
我之前寫過的一篇mpvue開發音頻類小程序踩坑和建議里面有講如何在小程序中使用vuex
。但遇到了個比較嚴重的性能問題。
1. 問題描述
我開發的是一個音頻類的小程序,所以需要將播放列表playList
,當前索引currentIndex
和當前時長currentTime
放進state.js
中:
const state = { currentIndex: 0, // playList當前索引 currentTime: 0, // 當前播放的進度 playList: [], // {title: '', url: '', singer: ''} }
每次用戶點擊播放音頻時,都會先加載音頻的播放列表playList
,然后播放時更新當前時長currentTime
,發現有時候播音頻時整個小程序非常卡頓。
注意到,音頻需每秒就得更新一次currentTime
,即每秒就做一次setData
操作,稍微有些卡頓是可以理解的。但我發現是播放列表數據比較多時會特別卡,比如playList的長度是100條以上時。
2. 問題原因
我開啟Vue.config._mpTrace = true
后發現一個規律:
當palyList
數據量小時,console
顯示造成的數據量更新數值比較小;當playList
比較大時,console
顯示造成的數據量更新數值比較大。
PS: 我曾嘗試將playList數據量增加到200條,每500ms的數據量更新達到800KB左右。
到這里基本可以確定一個事實就是:更新state
中的任何一個字段,將導致整個state
全量一起setData
。在我這里的例子,雖然我每次只是更新currentTime
這個字段的值,但依然導致將state中的其他字段如playList
,currentIndex
都一起做了一次setData
操作。
3. 解決問題
有兩個思路:
精簡state中保存的數據,即限制playList
的數據不能太多,可將一些數據暫存在storage
中
vuex
采用Module
的寫法能改善這個問題,雖然使用時命名空間造成一定的麻煩。vuex傳送門
一般情況下,推薦使用后者。我在項目中嘗試使用了前者,同樣能達到很好的效果,請繼續看下面的分享。
五、善用storage
1.為什么說要善用storage
由于小程序的內存非常寶貴,占用內存過大會非常卡頓,因此最好盡可能少的將數據放到內存中,即vuex
存的數據要盡可能少。而小程序的storage
支持單個 key允許存儲的最大數據長度為 1MB
,所有數據存儲上限為 10MB
。
所以可以將一些相對取用不頻繁的數據放進storage
中,需要時再將這些數據放進內存,從而緩解內存的緊張,有點類似Windows中虛擬內存
的概念。
2.storage換內存的實例
這個例子講的會有點啰嗦,真正能用到的朋友可以詳細看下。
上面講到playList
數據量太多,播放一條音頻時其實只需要最多保證3條數據在內存中即可,即上一首
,播放中的
,下一首
,我們可以將多余的播放列表存放在storage
中。
PS: 為了保證更平滑地連續切換下一首,我們可以稍微保存多幾條,比如我這里選擇保存5條數據在vuex中,播放時始終保證當前播放的音頻前后都有兩條數據。
// 首次播放背景音頻的方法 async function playAudio (audioId) { // 拿到播放列表,此時的playList最多只有5條數據。getPlayList方法看下面 const playList = await getPlayList(audioId) // 當前音頻在vuex中的currentIndex const currentIndex = playList.findIndex(item => item.audioId === audioId) // 播放背景音頻 this.audio = wx.getBackgroundAudioManager() this.audio.title = playList[currentIndex].title this.audio.src = playList[currentIndex].url // 通過mapActions將播放列表和currentIndex更新到vuex中 this.updateCurrentIndex(index) this.updatePlayList(playList) // updateCurrentIndex和updatePlayList是vuex寫好的方法 } // 播放音頻時獲取播放列表的方法,將所有數據存在storage,然后返回當前音頻的前后2條數據,保證最多5條數據 import { loadPlayList } from '@/api/audio' async function getPlayList (courseId, currentAudioId) { // 從api中請求得到播放列表 // loadPlayList是api的方法, courseId是獲取列表的參數,表示當前課程下的播放列表 let rawList = await loadPlayList(courseId) // simplifyPlayList過濾掉一些字段 const list = this.simplifyPlayList(rawList) // 將列表存到storage中 wx.setStorage({ key: 'playList', data: list }) return subPlayList(list, currentAudioId) }
重點是subPlayList
方法,這個方法保證了拿到的播放列表是最多5條數據。
function subPlayList(playList, currentAudioId) { let tempArr = [...playList] const count = 5 // 保持vuex中最多5條數據 const middle = parseInt(count / 2) // 中點的索引 const len = tempArr.length // 如果整個原始的播放列表本來就少于5條數據,說明不需要裁剪,直接返回 if (len <= count) { return tempArr } // 找到當前要播放的音頻的所在位置 const index = tempArr.findIndex(item => item.audioId === currentAudioId) // 截取當前音頻的前后兩條數據 tempArr = tempArr.splice(Math.max(0, Math.min(len - count, index - middle)), count) return tempArr }
tempArr.splice(Math.max(0, index - middle), count)
可能有些同學比較難理解,需要仔細琢磨一下。假設playList
有10條數據:
當前音頻是列表中的第1條(索引是0),截取前5個:playList.splice(0, 5)
,此時currentAudio
在這5個數據的索引是0
,沒有上一首
,有4個下一首
當前音頻是列表中的第2條(索引是1),截取前5個:playList.splice(0, 5)
,此時currentAudio
在這5個數據的索引是1
,有1個上一首
,3個下一首
當前音頻是列表中的第3條(索引是2),截取前5個:playList.splice(0, 5)
,此時currentAudio
在這5個數據的索引是2
,有2個上一首
,2個下一首
當前音頻是列表中的第4條(索引是3),截取第1到6個:playList.splice(1, 5)
,此時currentAudio
在這5個數據的索引是2
,有2個上一首
,2個下一首
當前音頻是列表中的第5條(索引是4),截取第2到7個:playList.splice(2, 5)
,此時currentAudio
在這5個數據的索引是2
,有2個上一首
,2個下一首
...
當前音頻是列表中的第9條(索引是8
),截取后5個:playList.splice(4, 5)
,此時currentAudio
在這5個數據的索引是3
,有3個上一首
,1個下一首
當前音頻是列表中的最后1條(索引是9
),截取后的5個:playList.splice(4, 5)
,此時currentAudio
在這5個數據的索引是4
,有4個上一首
,沒有下一首
有點啰嗦,感興趣的同學仔細琢磨下,無論當前音頻在哪,都始終保證了拿到當前音頻前后的最多5條數據。
接下來就是維護播放上一首或下一首時保證當前vuex中的playList
始終是包含當前音頻的前后2條。
播放下一首
function playNextAudio() { const nextIndex = this.currentIndex + 1 if (nextIndex < this.playList.length) { // 沒有超出數組長度,說明在vuex的列表中,可以直接播放 this.audio = wx.getBackgroundAudioManager() this.audio.src = this.playList[nextIndex].url this.audio.title = this.playList[nextIndex].title this.updateCurrentIndex(nextIndex) // 當判斷到已經到vuex的playList的邊界了,重新從storage中拿數據補充到playList if (nextIndex === this.playList.length - 1 || nextIndex === 0) { // 拿到只有當前音頻前后最多5條數據的列表 const newList = getPlayList(this.playList[nextIndex].courseId, this.playList[nextIndex].audioId) // 當前音頻在這5條數據中的索引 const index = newList.findIndex(item => item.audioId === this.playList[nextIndex].audioId) // 更新到vuex this.updateCurrentIndex(index) this.updatePlayList(newList) } } }
這里的getPlayList
方法是上面講過的,本來是從api中直接獲取的,為了避免每次都從api直接獲取,所以需要改一下,先讀storage,若無則從api獲取:
import { loadPlayList } from '@/api/audio' async function getPlayList (courseId, currentAudioId) { // 先從緩存列表中拿 const playList = wx.getStorageSync('playList') if (playList && playList.length > 0 && courseId === playList[0].courseId) { // 命中緩存,則從直接返回 return subPlayList(playList, currentAudioId) } else { // 沒有命中緩存,則從api中獲取 const list = await loadPlayList(courseId) wx.setStorage({ key: 'playList', data: list }) return subPlayList(list, currentAudioId) } }
播放上一首也是同理,就不贅述了。
PS: 將vuex中的數據精簡后,我所做的小程序在播放音頻時刷其他頁面已經非常流暢啦,效果非常好。
六、動畫優化
這個問題在mpvue開發音頻類小程序踩坑和建議已經講過了,感興趣的可以移步看一眼,這里只寫下概述:
如果要使用動畫,盡量用css動畫代替wx.createAnimation使用css動畫時建議開啟硬件加速最后
大致總結一下上面所講的幾個要點:
開發時打開Vue.config._mpTrace = true。
謹慎引入第三方庫,權衡收益。
添加數據到data中時要克制,能精簡盡量精簡。
圖片記得要壓縮,圖片在顯示時才渲染。
vuex保持數據精簡,必要時可先存storage。
性能優化是一個永不止步的話題,我也還在摸索,不足之處還請大家指點和分享。
感謝你能夠認真閱讀完這篇文章,希望小編分享的“mpvue如何優化性能”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。