知識(shí)
不管是網(wǎng)站,軟件還是小程序,都要直接或間接能為您產(chǎn)生價(jià)值,我們?cè)谧非笃湟曈X(jué)表現(xiàn)的同時(shí),更側(cè)重于功能的便捷,營(yíng)銷(xiāo)的便利,運(yùn)營(yíng)的高效,讓網(wǎng)站成為營(yíng)銷(xiāo)工具,讓軟件能切實(shí)提升企業(yè)內(nèi)部管理水平和效率。優(yōu)秀的程序?yàn)楹笃谏?jí)提供便捷的支持!
您當(dāng)前位置>首頁(yè) » 新聞資訊 » 小程序相關(guān) >
小程序性能優(yōu)化實(shí)踐總結(jié)
發(fā)表時(shí)間:2021-1-5
發(fā)布人:葵宇科技
瀏覽次數(shù):45
項(xiàng)目簡(jiǎn)述 & 問(wèn)題
先簡(jiǎn)單介紹一下項(xiàng)目,就是一個(gè)比較常規(guī)的點(diǎn)餐小程序。
界面如圖:
左邊是分類(lèi)菜單,右邊是長(zhǎng)列表,有多個(gè)分類(lèi)的商品,單個(gè)分類(lèi)滾動(dòng)完后可以繼續(xù)滾動(dòng)切換到下一個(gè)分類(lèi),同時(shí)左邊的分類(lèi)菜單選中態(tài)會(huì)跟著切換到當(dāng)前商品列表顯示的分類(lèi)。
考慮到更好的用戶(hù)體驗(yàn),以及參考了美團(tuán)等點(diǎn)餐小程序,這個(gè)商品列表的數(shù)據(jù)是一次性返回的。目前遇到的問(wèn)題就是,當(dāng)商品數(shù)量比較多時(shí),首次渲染時(shí)間很長(zhǎng),而且頁(yè)面會(huì)卡頓。
優(yōu)化方向
邏輯優(yōu)化
小聲bb:其實(shí)就是原來(lái)代碼(由于歷史原因)寫(xiě)得太爛了……OTL
先放個(gè)圖
小聲bb:連小程序都看不下去了,要警告了o(╯□╰)o
微信開(kāi)發(fā)者工具都有警告了,而且提示里面也有定位到具體代碼的位置,所以關(guān)鍵就是這個(gè) setData
?。?!
我們可以先看看官方對(duì)于小程序性能以及 setData
優(yōu)化的一些建議。
具體實(shí)踐:
1. setData
不能一次性傳太多數(shù)據(jù),如果列表太長(zhǎng),可以分開(kāi)渲染【比如轉(zhuǎn)化為二維數(shù)組,每次循環(huán)渲染一個(gè)數(shù)組】。
v1:簡(jiǎn)單粗暴版
// 每次渲染一個(gè)分類(lèi)
// 假設(shè)goodsList是一個(gè)二維數(shù)組
goodsList.forEach((item, index) => {
this.setData({
[`goodsList[${index}]`]: item
})
})
復(fù)制代碼
像上面這樣寫(xiě)會(huì)有一個(gè)問(wèn)題,頁(yè)面首屏渲染是快了,但是點(diǎn)擊頁(yè)面操作(比如加購(gòu)按鈕等),頁(yè)面會(huì)卡住,等一下才有反應(yīng),操作反饋延遲嚴(yán)重。
其實(shí)這是因?yàn)?,這個(gè)循環(huán)是把單次 setData
數(shù)量減少了,但是卻變成了循環(huán)多次 setData
,我們看著首屏顯示好了,但是其實(shí)其他分類(lèi)(其他數(shù)組)還在渲染,線(xiàn)程還是忙碌狀態(tài),JS 線(xiàn)程一直在編譯執(zhí)行渲染,點(diǎn)擊事件不能及時(shí)傳遞到邏輯層,邏輯層亦無(wú)法及時(shí)將操作處理結(jié)果及時(shí)傳遞到視圖層。
v2:定時(shí)器hack版
既然js線(xiàn)程忙著渲染,那我們可以強(qiáng)制讓它先停下來(lái)。于是有了v2的定時(shí)器hack版。
// 每次渲染一個(gè)分類(lèi)
let len = data.goodsList ? data.goodsList.length : 0;
let idx = 0
let timer = setInterval(() => {
if (idx < len) {
that.setData({
[`goodsList[${idx}]`]: data.goodsList[idx]
});
idx++
} else {
clearInterval(timer)
}
}, 15);
復(fù)制代碼
現(xiàn)在首屏渲染速度問(wèn)題解決了,點(diǎn)擊按鈕延遲響應(yīng)問(wèn)題也解決了。就是代碼有點(diǎn)hack,逼死強(qiáng)迫癥o(╯□╰)o
v3:大殺器——虛擬列表
虛擬列表簡(jiǎn)單說(shuō)原理就是只渲染當(dāng)前顯示屏幕區(qū)域以及前n屏和后n屏的數(shù)據(jù),用一個(gè)單獨(dú)的字段保存當(dāng)前需要顯示的數(shù)組(就是當(dāng)前一屏+前n屏+后n屏),每次列表滾動(dòng)的時(shí)候重新計(jì)算需要顯示的數(shù)據(jù),更新這個(gè)字段,頁(yè)面就會(huì)相應(yīng)更新了。這樣就能保證頁(yè)面上的元素節(jié)點(diǎn)數(shù)量不會(huì)太多,就可以支持大量數(shù)據(jù)的長(zhǎng)列表需求。
更詳細(xì)的原理和實(shí)現(xiàn)各位同學(xué)們可以自己搜一下,此處不展開(kāi)。
2. setData
可以支持顆粒更新,指定到具體的屬性。
比如加購(gòu)等操作,需要更新商品右上角的小數(shù)字,可以這樣寫(xiě):
this.setData({
[`goodsList[${categoryIndex}][${goodsIndex}].num`]: goodsItem.num
})
復(fù)制代碼
3. 跟頁(yè)面無(wú)關(guān)的數(shù)據(jù)不要保存在 data
,不要用 setData
更新,因?yàn)?setData
會(huì)觸發(fā)頁(yè)面渲染。
eg:
Page({
data: {
...
},
// 跟頁(yè)面渲染無(wú)關(guān)的數(shù)據(jù)
state: {
hasLogin: false,
},
...
})
// 更新的時(shí)候直接賦值就行
this.state.hasLogin = true
復(fù)制代碼
PS:或者甚至不需要掛載到 page
對(duì)象下,直接用普通變量保存。
4. 圖片大小優(yōu)化
在長(zhǎng)列表中圖片大小如果不加限制,大量的大圖會(huì)占用很多內(nèi)存,有可能導(dǎo)致iOS客戶(hù)端內(nèi)存占用上升,從而觸發(fā)系統(tǒng)回收小程序頁(yè)面。除了內(nèi)存問(wèn)題外,大圖片也會(huì)造成頁(yè)面切換的卡頓。
解決辦法就是根據(jù)當(dāng)前顯示的圖片區(qū)域大小,取尺寸剛好合適(2倍-3倍圖)的圖片。
建議圖片用CDN,一般CDN服務(wù)廠商提供圖片服務(wù)的都會(huì)提供裁剪圖片的接口,然后接口只返回原圖鏈接,前端根據(jù)需要傳參數(shù)裁剪圖片。前端具體做法可以寫(xiě)公共的圖片處理方法,或者自己封裝圖片組件。
5. 減少不必要的數(shù)據(jù)請(qǐng)求
比如在該點(diǎn)餐頁(yè)面進(jìn)入時(shí)需要獲取定位,然后根據(jù)定位獲取最近的門(mén)店,前面兩個(gè)接口都需要請(qǐng)求(具體可以根據(jù)業(yè)務(wù)需求),而最后如果獲取到的距離最近的門(mén)店跟上次一樣,則不需要重新獲取店鋪詳情和商品數(shù)據(jù)。
體驗(yàn)優(yōu)化
1. 合并短時(shí)間內(nèi)的多個(gè)loading提示
還是該點(diǎn)餐頁(yè)面流程,像上文說(shuō)過(guò)的,進(jìn)入頁(yè)面時(shí)需要獲取定位接口,等定位接口返回結(jié)果了再拿定位取值去獲取距離最近的店鋪,最后才是請(qǐng)求店鋪和商品數(shù)據(jù)。
這三個(gè)接口是串行的。此時(shí)如果我們每個(gè)接口都彈出一個(gè)loading提示,就會(huì)出現(xiàn)loading顯示一會(huì)兒,消失,又顯示一會(huì)兒,又消失……這樣的現(xiàn)象,這樣的體驗(yàn)是不太好的。
建議可以通過(guò)封裝請(qǐng)求,并且在請(qǐng)求里統(tǒng)一處理loading,來(lái)合并短時(shí)間內(nèi)多次發(fā)起請(qǐng)求的多個(gè)loading。
eg:
let showLoadingTimer = null;
let showRequestLoading = false; // 標(biāo)記是否正在顯示loading
/**
* 封裝request
* @param {*} {showLoading:是否需要顯示loading, options:request參數(shù),如url,data等}
*/
function request({showLoading = true, ...options}) {
// 顯示request loading
handleShowLoading(showLoading)
wx.request({
...
complete() {
// 關(guān)閉request loading
handleShowLoading(false)
}
})
}
/**
* 封裝request loading
* 短時(shí)間內(nèi)如果調(diào)用多次showLoading,會(huì)合并在一起顯示,而不是每個(gè)都閃現(xiàn)一下
* @param showLoading
*/
function handleShowLoading(showLoading) {
if (showLoading) {
// 顯示loading
clearTimeout(showLoadingTimer);
if (!showRequestLoading) {
showRequestLoading = true;
wx.showNavigationBarLoading();
wx.showLoading({ title: "加載中", mask: true })
}
} else {
// 200ms后關(guān)閉loading
showLoadingTimer = setTimeout(() => {
showRequestLoading = false;
wx.hideNavigationBarLoading();
wx.hideLoading()
}, 200)
}
}
復(fù)制代碼
2. 整個(gè)頁(yè)面初次加載時(shí)可以使用頁(yè)面loading動(dòng)畫(huà)或骨架屏,優(yōu)化加載中體驗(yàn)。
3. 靜默獲取、更新數(shù)據(jù)
比如這個(gè)點(diǎn)餐頁(yè)每次 onShow
都會(huì)調(diào)用定位接口和獲取最近門(mén)店接口,但是不顯示loading,用戶(hù)就沒(méi)有感知,體驗(yàn)比較好。
接口優(yōu)化
需要關(guān)注接口的粒度控制。 因?yàn)橛袝r(shí)候合并接口,前端可以減少一次請(qǐng)求,體驗(yàn)更好;但有時(shí)候如果接口的數(shù)據(jù)太多,響應(yīng)太慢,就可以考慮是否某部分?jǐn)?shù)據(jù)可以后置獲取,讓主要的頁(yè)面內(nèi)容先渲染出來(lái),根據(jù)這個(gè)設(shè)計(jì)來(lái)拆分接口。
比如項(xiàng)目中的點(diǎn)餐頁(yè)面,原來(lái)購(gòu)物車(chē)數(shù)據(jù)和商品規(guī)格彈窗顯示的詳情數(shù)據(jù)都是在獲取店鋪商品接口一次性返回的,而這個(gè)接口本來(lái)由于設(shè)計(jì)需要一次返回所有商品,就會(huì)造成數(shù)據(jù)量太大,而且后端需要查詢(xún)的表也更多。于是把獲取購(gòu)物車(chē),和商品詳情接口都拆分為單獨(dú)的接口,獲取店鋪商品接口的響應(yīng)時(shí)間就減少了,頁(yè)面也能更快顯示出來(lái)。
總結(jié)
其實(shí)上面提到的邏輯優(yōu)化和接口優(yōu)化很多都是細(xì)節(jié),并不是太高深的技術(shù),我們平時(shí)迭代的時(shí)候就可以注意。而體驗(yàn)方面的優(yōu)化則需要前端同學(xué)在前端技術(shù)以外更多關(guān)注用戶(hù)體驗(yàn)和設(shè)計(jì)方面的知識(shí)啦,而且這也是一個(gè)有追求的前端應(yīng)該具備的技能……←_←
相關(guān)案例查看更多
相關(guān)閱讀
- 百度排名
- 云南建設(shè)廳官方網(wǎng)站
- 云南建站公司
- 云南網(wǎng)站建設(shè)優(yōu)化
- 云南網(wǎng)站建設(shè)服務(wù)公司
- 云南衛(wèi)視小程序
- 云南網(wǎng)站建設(shè)哪家強(qiáng)
- 保山小程序開(kāi)發(fā)
- 專(zhuān)業(yè)網(wǎng)站建設(shè)公司
- 開(kāi)發(fā)制作小程序
- 云南網(wǎng)站開(kāi)發(fā)
- 大理小程序開(kāi)發(fā)
- 大理網(wǎng)站建設(shè)公司
- 云南小程序被騙
- 定制小程序開(kāi)發(fā)
- 區(qū)塊鏈
- 云南網(wǎng)站建設(shè)公司地址
- 江蘇小程序開(kāi)發(fā)
- 曲靖小程序開(kāi)發(fā)
- 云南小程序被騙蔣軍
- 云南網(wǎng)站建設(shè)專(zhuān)業(yè)品牌
- 網(wǎng)站建設(shè)開(kāi)發(fā)
- 百度自然排名
- 開(kāi)發(fā)框架
- 云南網(wǎng)站建設(shè)高手
- web開(kāi)發(fā)
- 網(wǎng)絡(luò)公司
- 高端網(wǎng)站建設(shè)公司
- 支付寶小程序被騙
- 微信小程序開(kāi)發(fā)入門(mén)課程