小程序性能优化

小程序性能优化从启动和运行两方面进行优化

启动性能

代码包体积

1. 合理使用分包加载(住包、独立分包、其他分包)

分包加载是小程序体积的和启动耗时优化最明显的手段。可按功能、使用频率和场景划分分包。

  • 承载更多功能;提升代码包体量,承载更多功能服务
  • 降低仔仔耗时:明显减少需下载的代码包大小,在不影响功能正常使用的前提,有效降低启动耗时
  • 降低代码注入耗时:未开启按需注入,小程序编译时会将所有js文件打包成同一个文件一次性注入,并执行所有(页面和自定义组件)代码逻辑。分包可以降低注入和实际执行的打码量,从而降低耗时。
  • 降低页面渲染耗时:分包可以避免不必要的组件和页面初始化
  • 降低内存占用:分包能够实现页面、组件和逻辑叫粗粒度的按需加载。从而降低内存占用
  1. 独立分包:独立分包可以独立于住包和其他分包,从独立分包进入小程序时,可以不加载住包和其他分包。通常将功能不是很复杂且相对独立、对启动性能要求很高的页面(如活动页、支付页、推广页···)归于独立分包中。

app.jsonsubpackages字段中对应的分包配置项中定义independent字段声明对应分包为独立分包。【moduleB】为独立分包。

限制:

  • 当用户从独立分包进入小程序时,app并不一定被注册,因此getApp()不一定能获得App对象。
  • 基础库2.2.4开始支持getApp({allowDefault: true}),在App未定义时返回默认实现。当主包加载,App被注册后,默认实现中定义的属性会被覆盖合并到真正的App中。
  • 在低于 6.7.2 版本的微信中运行时,独立分包视为普通分包处理,不具备独立运行的特性
  • 独立分包中
js 复制代码
const app = getApp({allowDefault: true}) // {}
app.data = 456
app.global = {}
  • 主包中
js 复制代码
// app.json
{
  "pages": [
    "pages/index",
    "pages/logs"
  ],
  "subpackages": [
    {
      "root": "moduleA",
      "pages": [
        "pages/rabbit",
        "pages/squirrel"
      ]
    }, {
      "root": "moduleB",
      "pages": [
        "pages/pear",
        "pages/pineapple"
      ],
      "independent": true
    }
  ]
}
  1. 分包预加载:当分包页跳转到其他分包页时,需要等到其他分包下载完成后才能进入页面,造成页面切换迟缓,影响小程序体验。分包预加载解决此延迟问题。 预下载分包行为在进入某个页面时触发,通过在 app.json 增加 preloadRule 配置来控制。
js 复制代码
// app.json
  "pages": ["pages/index"],
  "subpackages": [
    {
      "root": "important",
      "pages": ["index"],
    },
    {
      "root": "indep",
      "pages": ["index"],
      "independent": true
    }
  ],
 "preloadRule": {
    "pages/index": {
      "network": "all",
      "packages": ["important"]
    },
    "sub3/index": {
      "packages": ["path/to"]
    },
    "indep/index": {
      "packages": ["__APP__"]
    }
  }

preloadRule 中,key 是页面路径,value 是进入此页面的预下载配置,每个配置有以下几项:

字段 类型 必填 默认值 说明
packages StringArray 进入页面后预下载分包的 rootname__APP__ 表示主包。
network String wifi 在指定网络下预下载,可选值为: all: 不限网络 wifi: 仅wifi下预下载
  1. 分包异步化:分包异步化将小程序的分包从页面粒度细化到组件甚至文件粒度。使原本只能放在主包的部分插件、组件和代码逻辑可以剥离到分包中,并在运行时异步加载,进一步降低启动所需加载的包大小和代码量。分包异步化解决主包大小过度膨胀问题

跨分包JS代码引用:一个分包中的代码引用其它分包的代码时,为了不让下载阻塞代码运行,我们需要异步获取引用的结果。且配置占位组件 componentPlaceholder字段。

javascript 复制代码
// subPackageA/index.js
// 使用回调函数风格的调用
require('../subPackageB/utils.js', utils => {
  console.log(utils.whoami) // Wechat MiniProgram
}, ({mod, errMsg}) => {
  console.error(`path: ${mod}, ${errMsg}`)
})
// 或者使用 Promise 风格的调用
require.async('../commonPackage/index.js').then(pkg => {
  pkg.getPackageName() // 'common'
}).catch(({mod, errMsg}) => {
  console.error(`path: ${mod}, ${errMsg}`)
})

2. 避免非必要的全局自定义组件和插件

在APP.JSON中通过usingCompenents全局引入的自定义组件和plugins全局引入的插件,会在小程序启动时随主包一起下载和注入JS代码,影响启动耗时。

  1. 页面组件应在页面的配置json文件中配置
  2. 插件仅在某个分包中使用,应仅在分包中引用插件

3. 控制代码包内的资源文件

小程序代码包下载时会使用ZSTD算法进行压缩,图片、音频、视频、字体等资源文件占用较多体积。建议将代码包中此类资源尽可能部署到CDN,并使用URL引入

4. 及时清理无用代码和资源

除工具默认忽略和开发者声明忽略的文件外,小程序打包会将工程目录下所有文件都打入代码包内。意外的第三方库、废弃的代码、产品环境不需要的测试代码、未使用的组件、插件、扩展库等这些文件资源将影响代码包大小。

建议使用开发者工具提供的【代码静态依赖分析】,不定期分析包文件的构成和依赖关系,清理未使用的代码文件。也可使用工具设置的packOptions.ignore配置忽略规则

代码注入

  1. 按需注入:启用按需注入后,页面json和app.json中的usingConmponents配置的自定义组件,都会被视为页面依赖并进行注入和加载。需及时移除json中未使用的组件,并尽量避免全局声明属于频率低的自定义组件
js 复制代码
// app.json
{
// ...
  "lazyCodeLoading": "requiredComponents"
}
  1. 用时注入:在开启按需注入前提下,可通过【用时注入】特性,将组件在真正渲染时才进行代码注入,进一步降低小程序的启动和首屏时间。

在已经指定 lazyCodeLoadingrequiredComponents 的情况下,为自定义组件配置 占位组件 componentPlaceholder,组件就会自动被视为用时注入组件。

js 复制代码
// app.json
{
  "usingComponents": {
    "comp-a": "../comp/compA",
    "comp-b": "../comp/compB",
    "comp-c": "../comp/compC"
  },
  "componentPlaceholder": {
    "comp-a": "view",
    "comp-b": "comp-c"
  }
}
  1. 启动过程中尽量减少同步API的调用,避免阻塞当前JS线程(常见API: getSystemInfo/getSystemInfoSyncgetStorageSync/setStorageSync)

在小程序启动流程中,代码同步执行 APP.onLaunch、App.onShow、Page.onLoad、Page.onShow

  1. 避免启动过程中进行复杂运算,阻塞当前JS线程,影响启动耗时

首屏渲染

  1. 使用【按需注入------lazyCodeLoading】和【用时注入------componentPlaceholder】结合
js 复制代码
// app.json
{
 "lazyCodeLoading": "requiredComponents",
  "usingComponents": {
    "comp-a": "../comp/compA",
    "comp-b": "../comp/compB",
    "comp-c": "../comp/compC"
  },
  "componentPlaceholder": {
    "comp-a": "view",
    "comp-b": "comp-c"
  }
}
  1. 启用初始化渲染缓存------initialRenderingCache
js 复制代码
// app.json
{
    "initialRenderingCache": "static"
}
  1. 避免引用未使用的自定义组件。及时清理usingComponents对象
  2. 精简渲染数据
  • 渐进式渲染,优先展示页面关键部分,延迟渲染非关键部分
  • 与视图无关的数据尽量不放在data中
  1. 提前首屏数据请求
  1. 缓存请求数据:getStorage,setStorage
  2. 骨架屏

其他

小程序版本更迭,会发生如下,影响启动耗时。需合理规划版本发布

  • 用户需要重新获取小程序的基础信息
  • 进行小程序代码包的增量更新
  • 重新生成JS代码包的Code Cache
  • 重新生成初始化渲染缓存

运行时性能

1. 合理使用 setData

小程序时逻辑层和视图层双线程运行,不能直接进行数据共享,需要进行数据序列化、跨线程\进程的数据传输、数据反序列化,因此数据传输是异步、非实时的。setData流程:

  • 逻辑乘虚拟DOM树的遍历和更新,触发组件生命周期和observer等
  • 将data从逻辑层传输到视图层
  • 视图层虚拟DOM树的更新、真实DOM元素的更新并触发页面渲染更新
  1. data中应只包含渲染相关的数据:setData应只对渲染数据进行更新
  2. 控制setData使用频率:仅在需要页面更新时调用setData,对连续的setData调用尽可能合并(避免逻辑层JS线程持续繁忙,无法及时响应事件)
  3. 选择合适的setData调用范围:组件的setData调佣只会引起当前组件和子组件的更新,对频繁更新的元素封装为独立组件(如倒计时)
  4. setData应只传发生变化的数据:嵌套对象中数据改变,应精准到具体字段调用setData(传输数据量会影响通讯耗时)
  5. 控制后台页面的setData:页面切后台后,应尽量避免setData或延迟到onShow再执行

2. 渲染性能优化

  1. 适当监听页面和组件得scrpll事件:非必要不使用;实现滚动相关动画时优先考虑滚动驱动动画(scroll-view)或WXS响应事件。不添加onPageScrolll(){} 空事件
  2. 选择高性能恶的动画实现方式:优先CSS渐变、动画或框架提供得动画实现方式;WXS调整系节点style属性
  3. 使用IntersectionObserver监听元素曝光
  4. 控制WXML节点数量和层级数量
  5. 控制Page在构造时传入的自定义数据量:为了保证自定义数据在不同的页面也是不同实例,框架在页面创建时将这部分数据进行深拷贝,如果数据过多或者过于复杂,将带来很大的性能开销

3. 页面切换优化

视图层加载步骤:

  • 创建Webview
  • 注入视图层的小程序基础库
  • 注入主包的公共代码(独立分包除外)
  • 注入分包的公共代码(若页面位于分包中)
  • 注入页面代码 预加载步骤仅有前三步:
  • 创建Webview
  • 注入视图层的小程序基础库
  • 注入主包的公共代码(独立分包除外) 优化页面切换性能:
  1. 避免在 onHide和onUnload执行耗时操作
  2. 首屏渲染优化
  3. 提前发起数据请求(页面之间可通过EventChannel进行通信)
  4. 控制预加载时机:handleWebviewPreload------static、auto、manual

4. 资源加载优化

  1. 图片音频等静态资源压缩且放置于CDN
  2. 列表时使用懒加载优化
  3. 避免滥用Image组件的widthFix和heigjtFix模式,导致图片加载完成后再动态改变宽高,从而导致页面重排,发生抖动、卡顿现象
  4. 页面背景或banner,应尽量预先指定宽高,避免图片加载后在进行二次尺寸调整

5. 内存优化

  1. 合理使用分包加载
  2. 使用按需注入用时注入
  3. 编辑器的内存分析,及时清理冗余代码
  4. 及时解绑页面监听事件、清理定时器等,防止内存泄漏
相关推荐
罗狮粉 991 小时前
docker部署微信小程序自动构建发布和更新
docker·微信小程序·notepad++
Kika写代码14 小时前
【微信小程序】页面跳转基础 | 我的咖啡店-综合实训
服务器·微信小程序·小程序
源码哥_博纳软云15 小时前
JAVA同城服务场馆门店预约系统支持H5小程序APP源码
java·开发语言·微信小程序·小程序·微信公众平台
YUJIAN。16 小时前
使用uniapp开发微信小程序-框架搭建
微信小程序·小程序·uni-app
V+zmm101341 天前
基于微信小程序的乡村政务服务系统springboot+论文源码调试讲解
java·微信小程序·小程序·毕业设计·ssm
还这么多错误?!1 天前
uniapp微信小程序,使用fastadmin完成一个一键获取微信手机号的功能
微信小程序·小程序·uni-app
_院长大人_1 天前
微信小程序用户信息解密 AES/CBC/NoPadding 解密失败问题
微信小程序·小程序
wmd131643067121 天前
将微信配置信息存到数据库并进行调用
数据库·微信
407指导员1 天前
uniapp 微信小程序 页面部分截图实现
微信小程序·小程序·uni-app
三木吧1 天前
开发微信小程序的过程与心得
人工智能·微信小程序·小程序