【小程序】爆肝 3 天总结的微信小程序优化指南(收藏夹吃灰吧!)
前言
大家好,我是HoMeTown,最近要做一个小程序的项目,项目启动之前,回顾自己之前做过的小程序,感觉做的还是不够好,最近学习了一下小程序优化方案,这块总结一份个人笔记,以便参考,同时分享给大家,共勉。
关于微信小程序
微信小程序上线至今已经大约已经有5年
的时间,5年的时间,小程序的开发能力经过微信团队的不断努力优化,已经日益完善,不再像之前一样,翻翻文档就能完成一个简易的项目了,特别是性能优化方面,会优化与不会优化更是对产品的效果有着决定性的影响。
哪些部分需要优化?
- 首页白屏现象
- Loading加载时间过长,页面好久不显示
- 点击页面链接,页面跳转迟钝
- 按钮单击无响应
- 长内容列表,内容越多,越卡顿
- …
有了优化的方向,就可以根据问题逐一诊断了
小程序的启动流程?
运行载体
- iOS、Mac
- Android、PC
- 微信开发者工具
环境准备
- 小程序运行进程及运行环境准备
- 代码包下载、校验及初始化
- 视图层系统组件、WebView容器和原生组件的初始化
- 原生组件的初始化
- 逻辑层JS引擎初始化及域创建
代码注入
- 框架及第三方基础代码的初始化
- 小程序基础库注入
- 扩展库注入
- 插件、自定义组件注入
- 开发者代码注入
- 逻辑层代码「这里会派发
App.onLaunch
还有App.onShow
这些事件」 - 视图层代码
- 逻辑层代码「这里会派发
首屏渲染
- 逻辑层页面初始化,这个时间点是
initDataSendTime
,会派发Page.onLoad
事件 - 视图层时间点走到
viewLayerReaderStartTime
,会派发Page.onShow
事件 - 开发者代码从后端拉取,准备data数据
- 页面渲染
- 视图层时间点走到
viewLayerReaderEndTime
,会派发Page.onReady
事件,意味着首屏渲染完成
启动方式
冷启动
小程序在用户设备上第一次打开或者是销毁之后再打开,或者是30分钟以后
热启动
热启动是相对于冷启动而言的,热启动是小程序启动的一种优化机制,小程序进入后台30分钟以内再次进到前台,可以直接从后台状态然后回复到前台,所以,在这种情况下,刚刚那个代码注入
、首屏渲染
等基础工作就不会再执行了,设置App.onLaunch
、Page.onLoad
等这些一次性的生命周期,也不会有了。
结论
由此,可以得出,要做小程序的性能优化,主要是做冷启动
这块的优化以及运行时渲染性能的一个优化,小程序冷启动流程里涉及到一些程序和生命周期。
生命周期
在小程序中App和Page都有他们各自的生命周期函数。
App
- onLaunch,监听小程序初始化的事件
- onShow 监听小程序启动或切前台的事件
- onHide 监听小程序切后台的时间
Page
- onLoad 监听页面加载
- onShow 监听页面显示
- onReady 监听页面初次渲染完成
- onHide 监听页面隐藏
- onUnload 监听页面卸载
优化技巧
使用骨架屏
骨架屏的目的是为了减缓用户等待的情绪
使用
如图,在小程序开发者工具中,点击这里,生成骨架屏代码
然后他会生成两个文件:index.skeleton.wxml
& index.skeleton.wxss
分别在index.wxml
& index.wxss
引入
总结
- 在data数据对象中默认设置loading等于true。
- 不要直接修改生成的骨架屏的一个代码。通过配置去修改。
- **不要过度去使用骨架屏。一般只给主页去添加骨架屏效果 **
优化长列表
优化长列表,使用recycle-view
& recycle-item
虚拟DOM组件,在渲染的时候需要知道每个循环单元的一个高度,这是消费代码需要传递给组件的,在recycle-view组件里面,用户滑动的是数据而不是组件本身。
使用
首先初始化package.json
// npm初始化package.json文件
npm init -y
安装
// 安装 miniprogram-recycle-view插件
npm install --save miniprogram-recycle-view
构建依赖
生成miniprogram_npm
目录
组件内引用
代码中使用
list.wxml
<recycle-view batch="{{batchSetRecycleData}}" id="recycleId" catchscroll="onScroll"><view slot="before">长列表前面的内容</view><recycle-item wx:for="{{recycleList}}" wx:key="id"><view><image style='width:80px;height:80px;float:left;' src="{{item.image_url}}"></image>{{item.idx+1}}. {{item.title}}</view></recycle-item><view slot="after">长列表后面的内容</view>
</recycle-view>
list.js
const createRecycleContext = require('miniprogram-recycle-view')
Page({onReady: function () {var ctx = createRecycleContext({id: 'recycleId',dataKey: 'recycleList',page: this,itemSize: this.itemSizeFunc})ctx.append([{image_url: 'https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/09883c4389f642829c96b6216eebea85~tplv-k3u1fbpfcp-watermark.image?',idx: 1,title: '你好'}])// ctx.update(beginIndex, list)// ctx.destroy()},onScroll() {console.log('scroll')},itemSizeFunc: function (item, idx) {console.log(item)return {width: 375,height: 100}}
})
总结
代码写起来不是那么舒服,组件使用不友好,但是对性能确实还不错。
使用页面容器
有时候我们在页面上会弹出一些特定的半屏窗口,例如登录窗口。这时候如果用户在iOS设备上使用了左滑手势或者是在Android设备上单击了物理返回键,会造成页面跳转到上一个页面,这在大多数情况下它并不是用户的真实本意,用户可能只是想将当前弹出的半屏的假页面给它关掉。
page-container
页面容器,是不需要引入便可以使用。
使用
<page-container :show="{{show}}"> ...
</page-container>
总结
这个组件其实就是防止用户的左滑
或者按键返回
误操作,导致整个页面回退的问题。
优化动画效果
实现动画的方式:
- 是使用Animation对象,实现CSS动画
- 使用页面或组件对象,拥有的animate方法实现的关键帧动画
- 使用滚动事件驱动的响应式动画
- 通过WXS脚本,实现了一个样式动画
- 通过第三方库实现
animate.css
代码按需注入
代码懒加载
使用
// app.json
"lazyCodeLoading": "requiredComponents"
出现以下提示,代表成功
静态初始化渲染缓存
第一次页面运行时,由微信客户端负责将页面在本地的某个区域缓存起来,下次在真正的页面未加载完成前,先展示这个缓存过的页面。
使用
// xxxx.json
"initialRenderingCache": "static"
动态初始化渲染缓存
与静态初始化渲染缓存,动态初始化渲染缓存可以设置动态缓存的数据,放在onReady
生命周期中
使用
// xxx.json
"initialRenderingCache": "dynamic"
// xxx.js
// 设置动态缓存数据
this.setInitialRenderingCache({customersList: customerList
})
如果出现以下的信息,不用在意。
在手机里会有一条成功的信息:
update view with init data
分包
小程序包大小规定,单个代码包不超过2MB,总包大小不超过20MB,所以到我们业务庞大,代码量大导致项目大小上升,就必须用分包的形式,解决这个问题。
使用
// app.json
{"pages": [// "pages/user/index"],"subpackages": [{"root": "user","pages": ["pages/user/index"]}]
}
独立分包
使用
{"pages": [// "pages/user/index"// "pages/goods/index"],"subpackages": [{"root": "user","pages": ["pages/user/index"]},{"root": "goods","pages": ["pages/goods/index"],"independent": true // 独立分包关键配置}]
}
// pages/goods/index.js
const app = getApp({allowDefault: true}) // 独立分包中getApp为空,这里设置默认值
独立分包之后访问独立分包页面,主包和组件是不会被加载的,所以要分实际业务场景,进行分包
分包预加载
使用
"preloadRule": {
// 分包root路径+后面的路径"goods/pages/detail/index": {"network": "all","packages": ["__APP__"]}
}
看到这个提示,表示成功
总结
- tabbar最好自己实现
- 所有在根目录下的文件,如果没有分包,都会打包进主包,所以一般情况下,只放一个首页进主包
- 分包配置需要指定一个
root
目录,该目录下所有的文件都会自动被分割到这个分包里 - 对于相对独立的页面(例如分享页),可以进行独立分包,独立分包的页面会有「返回首页的按钮」,一般队里分包里,都需要设置
分包预加载
使用占位组件
使用占位组件延迟加载自定义组件
使用
创建一个名称为index_addons
的一个组件分包
// app.json
"subpackages": [{"root": "index_addons","pages": []}
]
修改主页配置
{"componentPlaceholder": {"stopwatch": "view" // 欲用作占位组件}
}
在stopwatch中添加代码
调试
- 设置为2g网
- 本地设置里,设置
懒注入占位组件调试
如果没有这个选项,请确认是否有配置 "lazyCodeLoading": [requiredComponents]
分包异步化
- require
- require.async
注意,只支持相对路径
使用
const { default: getNavList } = await require.async("../../../index_addons/compopnents/get_nav_list.js")
视图代码优化技巧
动态列表渲染里优化wx:key的使用
确保wx:key
的值是唯一值
如果列表元素是单一的基本数据类型,并且是唯一的,这时候我们可以直接写成this,这里这个this,就代表当前数据列表里面的数据元素
<view wx:for="{{textList}}" wx:key="*this"></view>
如果列表元素是静态的,只渲染一次,那么可以直接用index
<view wx:for="{{swipers}}" wx:key="index"></view>
如果数据是从后台获取的,那么wx:key
需要有一个唯一值
<view wx:for="{{customerList}}" wx:key="{{index}}"></view>
绑定视图事件
使用catch
代替bind
,减少dataset
的数据运输量,因为我们在大多数情况下,我们的事件不需要冒泡,所以bind
很浪费性能,catch
是不会冒泡的,事件传递某些信息的时候,需要什么传什么,不要一刀切,图省事,传递一个很大的对象,如果需要整个对象,建议使用index
进行传递
<view class="submit-btn" catchbind="onViewDetail" data-index="index">view detail</view>
防抖&节流
节流
节流顾名思义就是控制某段JS代码的执行频率
function throttle(method, wait = 50) {let previous = 0return function(...agrs) {let context = thislet now = new Date().getTime()if(now - previouts > wait) {method.apply(context, args)previous = now} else {console.log("节流少许")}}
}
防抖
顾名思义就是防止抖动,避免把一次时间当做多次处理,敲击键盘就是一个经常都会遇到的防抖操作场景
function debounce(func, wait = 50) {let timer = nullreturn function (...args) {const contest = thisif(timer) {clearTimeout(timer)console.log("防抖少许")}timer = setTimeout(() => {func.call(context, ...args)}, wait)}
}
组件中使用
const {default:debounce} = require(../../../library/optimus/debounce.js)
const {default:throttle} = require(../../../library/optimus/throttle.js)onScrolllToLower: throttle(function(e) {...
})onTapCustomerItem: debounce(function(e) {..
})
尽量少的使用重渲染和wxml标签
官方建议:
总页面节点数少于1000个,节点树深度层级少于30层,子节点数不大于60个
所以,在开发过程中,能用<text>
,就不用<view>
,能用文本
,就不用<text>
,对于循环列表中,能用<block>
就不用<view>
WXSS优化技巧
给滚动组件开启惯性滚动
-webkit-overflow-scrolling: touch;;
使用hover-class实现按钮的单击态
<button class="submit-btn" hover-class="submit-btn__hover"></button>
.submit-btn {...
}
.submit-btn__hover {...
}
使用gulp工具删除无用的wxss样式代码
安装
npm install gulp -g
npm install --save-dev gulp gulp-cleanwxss
配置
/tools/gulpfile.js
const gulp = require("gulp")
const cleanwxss = require("gulp-cleanwxss")// 处理父目录下的样式文件,输出到当前目录下的dist
gulp.task("default", (done) => {group.src("../minniprogram/index/pages/*/*.wxss").pipe(cleanwxss({ log: true })).pipe(gulp.dest("./dist"))done()
})// 处理分包下的样式文件
gulp.task("goods", (done) => {group.src("../minniprogram/goods/pages/*/*.wxss").pipe(cleanwxss({ log: true })).pipe(gulp.dest("./dist"))done()
})
执行
gulp default
gulp goods
CV
将生成出来的样式文件复制到对应目录即可
UI交互优化技巧
使用padding扩大可点击区域大小
.submit-btn {...padding: 10px;
}
使用伪元素扩大可点击区域大小
.submit-btn {position: relative;...
}
.submit-btn::after {content: '',position: absolute;top: -20px;right: -20px;bottom: -20px;left: -20px;}
脚本优化技巧
清理定时器
clearTimeout(timer1)
使用wx.onXxx全局绑定,有一个监听,必须有一个反监听
// 及时释放本页范围内添加的全局监听器
onLoad() {wx.onThemeChange(this.themeChangeHandler)
}
onUnload() {wx.offThemeChange(this.themeChangeHandler)
}
模拟器测试需要在app.json
中添加
"darkMode": "true"
小心使用全局对象,适当时机清理
setData调用优化
不要多次分开调用setData,尽量合并
// bad
if(this.data.gender === '1') {this.setData({genderName: '男'})
} else if(this.data.gender === '0') {this.setData({genderName: '女'})
} else {this.setData({genderName: '未知'})
}// good
let genderName = '未知'
if(this.data.gender === '1') genderName = '男'
if(this.data.gender === '0') genderName = '女'
this.setData({genderName,
})
不准备渲染的数据,不要放在data对象中
Page({allList: [],pageNum: 1,pageSize: 10,data: {list: []}
})
通过index局部更新列表数据
this.setData({[this.data.customerList[index].title]: item.title+='---'
})
网络请求优化技巧
减少不必要的网络请求,使用本地缓存数据
技术点:Storage
优化网络请求参数,提高网络请求效率
enableCache: true,
enableHttp2: true,
enableQuic: true
优化网络请求的并发数,分优先级
npm i priority-async-queue
request.js
const PriorityAsyncQueue = require('priority-async-queue')
const queue = new PriorityAsyncQueue(10) // default 10const low = "low", normal = "normal", mid = "mid", high = "high", "urgent" = "urgent"export const priority = { low, normal, mid, high, urgent }....return new Promise((resolve, reject) => {queue.addTask({ priority }. () => {wx.request(Object.assgin(args,{success: resolve,fail: reject})})
})
图片优化技巧
减少图片的请求次数
压缩图片大小
尽可能使用CDN图片或图片链接
尽可能使用webp格式图片
完结
小程序的优化大致就是从这些方面入手了,觉得有用的同学,点个赞,收个藏吧!
往期回顾
【VUE】从源码角度说清楚MVVM!实现v-model!真的很简单!
【小程序】爆肝 3 天总结的微信小程序优化指南(收藏夹吃灰吧!)相关推荐
- 收藏夹吃灰系列(二):教小师妹通过代码实现Swagger在线接口文档转word文档!教完后...?
话不多说,工具源码直接分享给大家吧: 如果最后觉得该代码生成器对你有所帮助,请不要吝啬你的赞,直接pia的点亮就完了啦,up up up!!! 如下就是全码,拿走!不谢!!助你趁早解放双手! 本地sw ...
- 小程序也能接广告了,微信小程序广告位投放指南!
小程序也能接广告了,微信小程序广告位投放指南! 3月15日消息,据爆料,微信已经开始秘密测试在小程序中投放广告,并且流传出了一份<微信小程序广告位投放指引>,意味着微信小程序已经准备开启广 ...
- python操作微信小程序云端数据库_微信小程序·云开发云数据库的基本使用-微信小程序云开发实例-腾讯云微信小程序...
微信小程序·云开发云数据库的基本使用-微信小程序云开发实例-腾讯云微信小程序 浏览量:1120 时间:2020-04-06
- php微信小程序多图上传,tp5实现微信小程序多图片上传到服务器功能
最近在做一个教育类的小商城的微信小程序,用到了上传多个图片文件到服务器端,这里做一个讲解,希望对大家有所帮助. 1,小程序端: 在wxml文件中: 删除 点击上传作业 在js文件中: Page({ / ...
- 小程序源码:宝宝起名神器微信小程序源码下载-多玩法安装简单
这款小程序支持输入姓氏自动起名,不满意还可以点击换一换来找到满意的 支持起两个字或者三个字的名字 另外小编也给该款小程序添加了几个流量给大家 下面就来看看小编的测试演示图吧! 小程序源码下载地址:小程 ...
- 微信小程序怎么添加到主屏幕将微信小程序放到手机桌面?
微信小程序在一些场景下使用还是非常方便,如果遇到需要经常使用的微信小程序,将该微信小程序添加到手机桌面上,下次直接点击打开将更方便. 例如:草柴微信小程序很多人每天都在用免费领取美团外卖红包优惠券.饿 ...
- 微信小程序怎么开通(自己申请开通微信小程序的方法)
微信小程序怎么开通(自己申请开通微信小程序的方法) 很多粉丝朋友想要了解微信小程序怎么开通,自己想要申请开发同微信小程序.本文瀚林就给大家分享自己开通微信小程序的方法. 在操作之前,首先要大家清楚明白 ...
- 微信小程序 某个页面直接返回首页(微信小程序回退到首页)
微信小程序 某个页面直接返回首页(微信小程序回退到首页) 打开小程序后,到三级页面后点击左上角的返回按钮,能够直接返回到首页 正常 A -> B -> C 都是通过 wx.navigate ...
- 《微信小程序开发实战》学习笔记chapter1微信小程序人门
Chapter01 微信小程序入门 1. 微信小程序介绍 1.1 什么是微信小程序 微信小程序是腾讯于2017年1月19日推出的一种不需要安装即可在微信平台上使用的应用.微信小程序和微信的原生功能应用 ...
最新文章
- Numpy数组图像基本操作方法,及截取ROI、增加行与列
- 【 MATLAB 】信号处理工具箱之波形产生函数 rectpuls
- 一次bug死磕经历之Hbase堆内存小导致regionserver频繁挂掉
- 深入理解Windows消息循环
- Echarts地图编写
- c语言fork()创建线程,操作系统的创建原语是fork()还是creat()?
- python用一行代码编写一个回声程序_使用Python的多回声测验
- 另一个伊甸国际服节奏榜(以下全为个人观点,仅供参考
- 百度快照劫持是什么意思?怎么解决
- 防火墙 蓝精灵DoS P127
- go学习 --- go协程
- 优酷视频怎么转二维码_优酷视频转二维码
- hive时空链战_时空链战Chain Strike游戏电脑版下载_时空链战Chain Strike最新电脑版下载_18183手机游戏下载...
- CAD绘制二维码(网页版)
- vue前端自动生成编号或者订单单号(日期+随机数)
- WIFI手机将登陆上海 打国际长途每分钟0.3元
- C++各行小数点对齐
- 生化危机4(来生/恶灵古堡IV)DVD/700M发布
- 关于Socket粘包、半包问题的解决方法
- CSS样式实现选择按钮
热门文章
- 收藏夹吃灰系列(二):教小师妹通过代码实现Swagger在线接口文档转word文档!教完后...?