內(nèi)存預(yù)警
小程序提供了監(jiān)聽內(nèi)存不足告警事件的 API:wx.onMemoryWarning[23]鸡捐,旨在讓開發(fā)者收到告警時(shí)及時(shí)釋放內(nèi)存資源避免小程序 Crash箍镜。然而對(duì)于小程序開發(fā)者來說,內(nèi)存資源目前是無法直接觸碰的色迂,最多就是調(diào)用 wx.reLaunch 清理所有頁面棧歇僧,重載當(dāng)前頁面,來降低內(nèi)存負(fù)荷(此方案過于粗暴诈悍,別沖動(dòng)侥钳,想想就好...)。
不過內(nèi)存告警的信息收集倒是有意義的苦酱,我們可以把內(nèi)存告警信息(包括頁面路徑、客戶端版本疫萤、終端手機(jī)型號(hào)等)上報(bào)到日志系統(tǒng)扯饶,分析出哪些頁面 Crash 率比較高,從而針對(duì)性地做優(yōu)化帝际,降低頁面復(fù)雜度等等蹲诀。
回收后臺(tái)頁面計(jì)時(shí)器
根據(jù)雙線程模型弃揽,小程序每一個(gè)頁面都會(huì)獨(dú)立一個(gè) webview 線程,但邏輯層是單線程的痕慢,也就是所有的 webview 線程共享一個(gè) JS 線程涌矢。以至于當(dāng)頁面切換到后臺(tái)態(tài)時(shí),仍然有可能搶占到邏輯層的資源塔次,譬如沒有銷毀的 setInterval名秀、setTimeout 定時(shí)器:
// Page A
Page({
onLoad() {
let i = 0
setInterval(() => { i++ }, 100)
}
})
即使如小程序的 <swiper> 組件,在頁面進(jìn)入后臺(tái)態(tài)時(shí)依然是會(huì)持續(xù)輪播的继榆。
正確的做法是汁掠,在頁面 onHide 的時(shí)候手動(dòng)把定時(shí)器清理掉考阱,有必要時(shí)再在 onShow 階段恢復(fù)定時(shí)器。坦白講羔砾,區(qū)區(qū)一個(gè)定時(shí)器回調(diào)函數(shù)的執(zhí)行,對(duì)于系統(tǒng)的影響應(yīng)該是微不足道的政溃,但不容忽視的是回調(diào)函數(shù)里的代碼邏輯董虱,譬如在定時(shí)器回調(diào)里持續(xù) setData 大量數(shù)據(jù),這就非常難受了...
避免頻發(fā)事件中的重度內(nèi)存操作
我們經(jīng)常會(huì)遇到這樣的需求:廣告曝光云头、圖片懶加載淫半、導(dǎo)航欄吸頂?shù)鹊龋@些都需要我們?cè)陧撁鏉L動(dòng)事件觸發(fā)時(shí)實(shí)時(shí)監(jiān)聽元素位置或更新視圖昏滴。在了解小程序的雙線程模型之后不難發(fā)現(xiàn)对人,頁面滾動(dòng)時(shí) onPageScroll 被頻發(fā)觸發(fā),會(huì)使邏輯層和視圖層發(fā)生持續(xù)通信姻几,若這時(shí)候再 “火上澆油” 調(diào)用 setData 傳輸大量數(shù)據(jù)势告,會(huì)導(dǎo)致內(nèi)存使用率快速上升培慌,使頁面卡頓甚至 “假死”。所以盒音,針對(duì)頻發(fā)事件的監(jiān)聽馅而,我們最好遵循以下原則:
onPageScroll 事件回調(diào)使用節(jié)流;
避免 CPU 密集型操作雄坪,譬如復(fù)雜的計(jì)算屯蹦;
避免調(diào)用 setData绳姨,或減小 setData 的數(shù)據(jù)量飘庄;
盡量使用 IntersectionObserver[24] 來替代 SelectorQuery[25]购撼,前者對(duì)性能影響更小碾盐;
大圖揩局、長(zhǎng)列表優(yōu)化
據(jù) 小程序官方文檔[26] 描述,大圖片和長(zhǎng)列表圖片在 iOS 中會(huì)引起 WKWebView 的回收孕豹,導(dǎo)致小程序 Crash十气。
對(duì)于大圖片資源(譬如滿屏的 gif 圖)來說砸西,我們只能盡可能對(duì)圖片進(jìn)行降質(zhì)或裁剪址儒,當(dāng)然不使用是最好的嫁佳。
對(duì)于長(zhǎng)列表立美,譬如瀑布流蝶俱,這里提供一種思路:我們可以利用 IntersectionObserver[27] 監(jiān)聽長(zhǎng)列表內(nèi)組件與視窗之間的相交狀態(tài)法挨,當(dāng)組件距離視窗大于某個(gè)臨界點(diǎn)時(shí)叉寂,銷毀該組件釋放內(nèi)存空間翁逞,并用等尺寸的骨架圖占坑溉仑;當(dāng)距離小于臨界點(diǎn)時(shí)浊竟,再取緩存數(shù)據(jù)重新加載該組件津畸。
然而無可避免地必怜,當(dāng)用戶快速滾動(dòng)長(zhǎng)列表時(shí)棚赔,被銷毀的組件可能來不及加載完,視覺上就會(huì)出現(xiàn)短暫的白屏丧肴。我們可以適當(dāng)?shù)卣{(diào)整銷毀閾值胧后,或者優(yōu)化骨架圖的樣式來盡可能提升體驗(yàn)感芋浮。
小程序官方提供了一個(gè) 長(zhǎng)列表組件[28],可以通過 npm 包的方式引入壳快,有興趣的可以嘗試纸巷。
參考資料
[1]
Taro: https://taro.aotu.io/
[2]
小程序性能評(píng)分規(guī)則: https://developers.weixin.qq.com/miniprogram/dev/framework/audits/performance.html
[3]
體驗(yàn)評(píng)分工具(Audits 面板): https://developers.weixin.qq.com/miniprogram/dev/framework/audits/audits.html
[4]
測(cè)速系統(tǒng): https://developers.weixin.qq.com/miniprogram/dev/framework/performanceReport/
[5]
JS Tree-Shaking: https://developers.google.com/web/fundamentals/performance/optimizing-javascript/tree-shaking
[6]
PurifyCSS: https://github.com/purifycss/purifycss
[7]
使用分包: https://developers.weixin.qq.com/miniprogram/dev/framework/subpackages/basic.html
[8]
獨(dú)立分包: https://developers.weixin.qq.com/miniprogram/dev/framework/subpackages/independent.html
[9]
web-view: https://developers.weixin.qq.com/miniprogram/dev/component/web-view.html
[10]
小程序開發(fā)文檔: https://developers.weixin.qq.com/miniprogram/dev/component/web-view.html
[11]
數(shù)據(jù)預(yù)拉取: https://developers.weixin.qq.com/miniprogram/dev/framework/ability/pre-fetch.html
[13]
分包預(yù)下載: https://developers.weixin.qq.com/miniprogram/dev/framework/subpackages/preload.html
[14]
關(guān)鍵渲染路徑(Critical Rendering Path): https://developers.google.com/web/fundamentals/performance/critical-rendering-path
[15]
wx.request: https://developers.weixin.qq.com/miniprogram/dev/api/network/request/wx.request.html
[16]
WebP: https://developers.google.com/speed/webp
[17]
image 組件: https://developers.weixin.qq.com/miniprogram/dev/component/image.html
[18]
image 組件: https://developers.weixin.qq.com/miniprogram/dev/component/image.html
[19]
w3schools: https://www.w3schools.com/css/css_image_sprites.asp
[20]
事件循環(huán): https://github.com/aooy/blog/issues/5
[21]
數(shù)據(jù) diff 規(guī)則: https://nervjs.github.io/taro/docs/optimized-practice.html#%E5%B0%8F%E7%A8%8B%E5%BA%8F%E6%95%B0%E6%8D%AE-diff
[22]
Web Components: https://developer.mozilla.org/zh-CN/docs/Web/Web_Components
[23]
wx.onMemoryWarning: https://developers.weixin.qq.com/miniprogram/dev/api/device/performance/wx.onMemoryWarning.html
[24]
IntersectionObserver: https://developers.weixin.qq.com/miniprogram/dev/api/wxml/IntersectionObserver.html
[25]
SelectorQuery: https://developers.weixin.qq.com/miniprogram/dev/api/wxml/SelectorQuery.html
[26]
小程序官方文檔: https://developers.weixin.qq.com/miniprogram/dev/framework/performance/tips.html
[27]
IntersectionObserver: https://developers.weixin.qq.com/miniprogram/dev/api/wxml/IntersectionObserver.html
[28]
長(zhǎng)列表組件: https://developers.weixin.qq.com/miniprogram/dev/extended/functional/recycle-view.html
[29]
User-centric Performance Metrics: https://developers.google.com/web/fundamentals/performance/user-centric-performance-metrics
[30]
Reduce JavaScript Payloads with Tree Shaking: https://developers.google.com/web/fundamentals/performance/optimizing-javascript/tree-shaking
[31]
小程序開發(fā)指南: https://developers.weixin.qq.com/ebook?action=get_post_info&docid=0008aeea9a8978ab0086a685851c0a
[32]
小程序官方文檔: https://developers.weixin.qq.com/miniprogram/dev/framework/
[33]
Taro 官方文檔: https://taro.aotu.io/home/in.html
[34]
探究WebP一些事兒: https://aotu.io/notes/2016/06/23/explore-something-of-webp/index.html