前言
做小程序时,大家应该都有这样的体验。刚开始业务单纯,小程序只有简单两三个页面,随着业务的推进,代码文件越来越多,在维护起来各个代码文件看的眼花缭乱的同时,小程序的启动速度(冷启动)也越来越慢,在网络差时,小程序甚至会打开失败。
这个时候,“分包 ”和“按需注入”成为了大家开始关注的对象。
一、分包加载
这里只说下个人对于分包的一些见解归纳,具体使用规范和配置格式还要参见官方文档:【使用分包|微信开发文档】
1、什么是分包?
大家知道,小程序代码是在一个代码包内。在某些情况下,开发者需要将小程序代码包划分成不同的子包。确切的说,就是将部分页面代码单独放在指定的子包内。
每个使用分包小程序必定含有一个主包和若干分包。
在
app.json
中的subpackages
下配置的路径页面被打包成分包,subpackages
配置路径外的目录和其他公共资源将被打包到主包中。
- 主包:即放置默认启动页面/TabBar 页面,以及一些所有分包都需用到公共资源/JS 脚本;
- 分包:则是根据开发者的配置进行划分,也就是前边说的部分指定页面的代码。
2、为什么分包?
- 如果没有使用分包,小程序启动时,会下载整个小程序代码包,等待整个包下载完成再去进行展示。
- 如果使用了分包,在小程序启动时,默认会下载主包并启动主包内页面,当用户进入分包内某个页面时,客户端会把对应分包下载下来,下载完成后再进行展示。
所以,对小程序进行分包,可以优化小程序首次启动的下载时间,以及在多团队共同开发时可以更好的解耦协作。
简单来说,我把首次加载不必须的页面资源全放到分包里,这样页面首次加载需要下载的资源就会大大减少。小程序启动时间自然就提升了。不同开发人员各自维护自己分包的内容,也就自然实现了多人开发的解耦协作。
3、独立分包
还有一种情况,小程序有3-4个tab页面,而且依赖资源还挺多。这样无论怎么分,主包内容也挺多。我们需要首屏展示的页面非常简单,但是首次启动却不得的加载主包内容,影响打开速度。怎么办?此时可以尝试用独立分包。
独立分包是小程序中一种特殊类型的分包,可以独立于主包和其他分包运行。从独立分包中页面进入小程序时,不需要下载主包。当用户进入普通分包或主包内页面时,主包才会被下载。
独立分包不依赖主包即可运行,首屏页面配置成独立分包,打开时不用加载主包和其他分包的资源,这样可以很大程度上提升分包页面的启动速度。
但是有个重要前提: 独立分包中不能依赖主包和其他分包中的内容,包括 js 文件、template、wxss、自定义组件、插件等(使用 分包异步化 时 js 文件、自定义组件、插件不受此条限制)。
配置方法可参考: 【独立分包|微信开放文档】
4、分包预加载
使用分包,我们可以减少小程序启动时需要下载的资源。这样小程序启动效率提升了。但是启动后需要跳转到其他分包页面时,该分包页面所在的分包需要下载后才能打开这个页面。影响了后续页面的打开速度,怎么办?这时,小程序给我们提供了分包预加载的机制。
开发者可以通过配置,在进入小程序某个页面时,由框架自动预下载可能需要的分包,提升进入后续分包页面时的启动速度。对于独立分包,也可以预下载主包。
预下载分包行为在进入某个页面时触发,通过在 app.json
增加 preloadRule
配置来控制。 我们在访问需要打开其他分包页面的路径时预先加载好后续分包,就大大加快了后续分包页面的打开速度。
配置方法可参考: 【分包预加载|微信开放文档】
二、按需注入和用时注入
通过以上的分包加载,我们可以让每个包独立加载,实现了包的按需加载,提升了小程序的启动时间。但是还有没有进一步提升启动时间的空间?
参考文档:【按需注入和用时注入|微信开放文档】
1、按需注入
小程序启动的过程中,除了代码包下载以外,代码注入也是一个主要的耗时环节,如果只是分包加载,还有以下问题:
- 在小程序启动时,启动页面依赖的所有代码包(主包、分包、插件包、扩展库等)的所有 JS 代码会全部合并注入,包括包内其他未访问的页面。
- 同时包内的所有页面和自定义组件的 JS 代码会被立刻执行。这造成很多没有使用的代码在小程序运行环境中注入执行,影响注入耗时和内存占用。
这时我们会想,如果只注入并执行当前页面和当前页面的自定义组件的代码。是不是会更好,于是有了按需注入。
自基础库版本 2.11.1 起,小程序支持通过配置,有选择地注入必要的代码,以降低小程序的启动时间和运行时内存。
//app.json配置
{
"lazyCodeLoading": "requiredComponents"
}
启用按需注入后:
- 小程序仅注入当前访问页面所需的自定义组件和页面代码。未访问的页面、当前页面未声明的自定义组件不会被加载和初始化,对应代码文件将不被执行。建议开发者:
修改配置后务必确认小程序的表现正常
。 - 页面 JSON 配置中定义的所有组件和
app.json
中usingComponents
配置的全局自定义组件,都会被视为页面的依赖并进行注入和加载。建议开发者:尽量避免在全局声明使用率低的自定义组件,否则可能会影响按需注入的效果
。
2、用时注入
用时注入使当前页面渲染前只注入并执行当前页面相关的非自定义组件的代码文件,用占位组件
(例如简单的view组件)
替换自定义组件在页面的位置,进一步提升了小程序启动速度,在当前页开始渲染时,再注入自定义组件并换回占位组件。
在已经指定 lazyCodeLoading
为 requiredComponents
的情况下,为自定义组件配置 占位组件,组件就会自动被视为「用时注入」组件:
- 每个页面内,第一次渲染该组件前,该组件都不会被注入;
- 每个页面内,第一次渲染该组件时,该组件会被渲染为其对应的占位组件,渲染流程结束后开始注入;
- 注入结束后,占位组件被替换回对应组件。
三、总结
-
区别:
分包加载
是按需求加载不同功能模块的代码包,节省了非必要代码包的下载时间;按需注入
是在已经加载代码包后按照需求注入和执行当前需要的代码文件,节省了非相关页面代码文件的注入执行时间。 -
优缺点:
按需注入
可以在分包加载
的基础上进一步提升小程序启动时间;但是对代码文件依赖管理的要求比较高,如果有些全局方法和属性不是在当前页面引用的代码文件中声明赋值的,则在当前页面无法正常调用,增加了逻辑复杂性。 - 配置选择:按照需求选择,如果分包加载已经能够满足我们的需求,则不必为了追求极致而使用按需注入。