前言
使用Taro开发的小程序项目运行两年多了,随着需求迭代越来越多,页面功能增加了不少,都没怎么注意小程序的性能。这段时间参考官网文章优化下代码,提升小程序使用的性能。
下面是使用微信小程序开发者工具的 Audits 面板跑的体验评分,基本把每个页面都覆盖了。可以看到评分低了些。
因此,针对 Audits 面板提供的优化建议,以及参考Taro的性能优化指南,重新调整了项目代码。下面记录下做了哪些操作。Taro版本3.6.11
。
虚拟列表
首先第一个肯定是优先优化长列表,以前显示数量不多,后端接口也没做分页。主要是产品需求需要进入页面能够自动滚动到用户最近学习某个位置上,那么做分页的话,就没办法做自动滚动了。可是如今数据量变多了,白屏率瞬间上来了。
Taro提供了虚拟列表组件,同时支持unlimitedSize
属性,列表单项大小变化时,列表显示会重新调整。
虚拟列表组件必须得提供高度,同时负责小程序的导航栏是自定义的,所以需要计算下
import { getSystemInfoSync, getMenuButtonBoundingClientRect } from '@tarojs/taro';
// 导航条
const headerBoundingClient = getMenuButtonBoundingClientRect();
// 页面高度
const { windowHeight } = getSystemInfoSync();
// 列表高度
const LIST_HEIGHT = windowHeight - headerBoundingClient.height - headerBoundingClient.top;
另外,列表单项也要给个初始高度itemSize
,即使是动态变化的。这里要注意,如果我们的列表单项样式是rpx的,记得换算成px。
优化后效果,获取数据后基本就秒渲染了。
非首屏内容,nextTick再渲染
针对页面内容渲染较多的,导致页面进入时白屏率过高,那么可以首屏的内容正常渲染,其他内容延时渲染,这样可以减少用户等待时间。Taro提供了 nextTick
api,刚好可以给自己的项目代码重新修改下。写法例如下
const [mounted, setMounted] = useState(false);
useEffect(() => {
Taro.nextTick(() => {
setMounted(true);
});
}, []);
if (mounted) {
// 开始渲染
}
return null
为了方便,抽成一个组件可在多个地方使用
/**
* 使用该组件包裹,延迟渲染
*/
const NextTickComponent: React.FC = ({ children }) => {
const [mounted, setMounted] = useState(false);
useEffect(() => {
Taro.nextTick(() => {
setMounted(true);
});
}, []);
if (mounted) {
return <>{children}</>;
}
return null;
};
export default NextTickComponent;
// 用法
<NextTickComponent>
<Content />
</NextTickComponent>
智能提取分包依赖
这个也是官网文档 智能提取分包依赖 有介绍。就是把主包没用到,而只在分包用的代码,抽离文件到分包里,减少主包大小。配置比较简单,官网描述很详细了。
// config/index.js
config = {
// ...
mini: {
// ...
optimizeMainPackage: {
enable: true,
},
},
}
主包减小了,但是各个分包大小有所增大。如果是微信小程序,有必要的话可别忘了配置 分包预下载
抽离公共文件与微信小程序的按需注入
Taro默认配置会把所有公用代码抽离到一个文件里,所以根据不同项目的需求,需要自行调整下。比如,作者负责的项目在分包中使用了antv
库,这库可不小,而且只有某些页面才会用到,很有必要单独抽离下。配置如下
// config/index.js
mini: {
webpackChain(chain) {
// 单独抽离 antv 依赖
chain.merge({
optimization: {
splitChunks: {
cacheGroups: {
antv: {
name: 'subPackages/antv-vendors',
test: /[\\/]node_modules[\\/](@antv)[\\/]/,
priority: 10010
}
}
}
}
});
},
}
然后别忘了我们在需要使用的页面引入。
mini: {
addChunkPages(pages) {
// 页面引入 antv 依赖
pages.set('subPackages/example1/index', ['subPackages/antv-vendors']);
pages.set('subPackages/example2/index', ['subPackages/antv-vendors']);
},
}
这样配置之后,如果是微信小程序的话作用不大,因为通常情况下,在小程序启动时,启动页面依赖的所有代码包(主包、分包、插件包、扩展库等)的所有 JS 代码会全部合并注入,包括其他未访问的页面以及未用到自定义组件,同时所有页面和自定义组件的 JS 代码会被立刻执行。
所以我们把文件分离后,还需要配置微信小程序的 按需注入,这样才能发挥最大作用。
配置也非常简单,只需加上一行
// app.config.ts
export default {
lazyCodeLoading: 'requiredComponents',
}
跳转预加载
跳转预加载在 官方文档 有说明,小程序由 A 页面跳转到 B 页面的过程中,从 A 页面发起跳转到 B 页面触发 onLoad,有着 300~400 毫秒的延时。我们可以在跳转的同时,开始请求相对慢的接口,能够在进入B页面时尽快拿到数据。
// A页面
Taro.preload({
RequestPromise: getData(),
})
Taro.navigateTo({ url: '/pages/B/B' })
// B页面
useEffect(() => {
Taro.getCurrentInstance().preloadData?.RequestPromise?.then(res => {
// 获取数据,更新渲染
})
}, []);
我们可以在跳转前,先执行请求函数生成 promise实例,然后在B页面拿到数据。
CustomWraper
这个是 Taro提供的小程序性能优化组件,用它去包裹我们项目中比较复杂,更新渲染有性能问题的组件,有需要用就完事了。
<CustomWrapper>
<GoodsList>
</CustomWrapper>
图片优化
H5与小程序的图片资源大小比较重要,作者犯了个错,设计师提供的UI稿是750尺寸的,作者开发pc页面时习惯性切图下载2倍比例的图片,保证图片显示高清。但是在H5与小程序中这样做把图片加大了,但是有效显示区域不需要那么大。比如 UI稿 中 50x50px 的图片,我下载成 100x100px。但是在iphone6/7/8 中只需要 50x50rpx,即25x25px。由于自己的不正确操作,不得不把之前开发的切图资源重新缩小一遍。
另外,有必要使用 tinypng 之类的压缩工具把图片再压缩下。同时可以在不同的设备环境使用不同的cdn图片资源。
最后,为 Image 标签设置 lazyload 属性,获取懒加载的功能。要注意的是页面要在三屏以上,懒加载功能才会生效,就是说上一屏、当前屏、下一屏的图片是立刻加载的,之外的才会懒加载。
缓存策略
例如微信小程序的wx.request
提供了enableCache
属性。我们也可以自行使用Storage等实现缓存优先策略。不像文章、商品等展示页面,由于作者负责的小程序对数据实时性要求比较高,就暂时不做这个处理了
优化后体验评分
最后最后,贴一下优化后重新跑的评分,效果还是蛮不错的。