一、流加载是什么?
用一句话来解释【流加载】,那就是“下载程序包的同时加载包内的文件”,下载与加载并发可以加速小程序首次无缓存启动的时间。
二、实现方案
1.1 使用pkg包替代zip包
在【流加载方案】之前,小程序的文件都是压缩到zip包内的,尽管zip包的体积更小,但zip包内的文件需要等完整的zip包下载好后才能解压出来使用,解压也需要时间。
在【流加载方案】中,我们改用pkg包来装载小程序的文件,pkg包是未压缩过的二进制文件包,可以直接读取包内指定区域的二进制数据。pkg包相比于压缩的zip包体积会更大,通过开启CDN智能压缩服务,在pkg包请求过程中,服务器对返回的pkg数据进行gzip编码,压缩重复的字符串等,可以减少pkg包的传输大小,从而缩短下载时间。
下图可见pkg包内的文件分布结构,仅举例,不同的小程序文件顺序可能不同。
| 文件标识符"PKG"(8字节) | 文件版本号(8字节) |
| 扩展信息长度(8字节) | 扩展信息 |
| 所包含的文件数量(8字节)|
| 文件 1 文件名长度(2字节) | 文件 1 文件名 | 文件 1 偏移量(4字节) | 文件 1 大小(4字节) |
| 文件 2 文件名长度(2字节) | 文件 2 文件名 | 文件 2 偏移量(4字节) | 文件 2 大小(4字节) |
| ... |
| 文件 1 二进制内容 | 文件 2 二进制内容 | ... |
1.2 资源加载时机提前
在pkg格式程序包的支持下,我们不必等待包下载完成后才去加载资源,资源加载的时机得以提前。
流加载优化前后的启动阶段流程分别如下:
meta信息获取 | |||
下载zip包 | |||
解压zip包 | |||
加载文件渲染出首帧 |
meta信息获取 | |||
下载pkg包 | |||
加载文件并渲染出首帧 |
假设某个版本的小程序A在改造前后包内文件不变,资源加载顺序相同,提前加载文件可以使得小程序首屏渲染更快出现。
1.3 小程序包体改造优化
包体改造主要是优化小程序的首屏加载时间,把app-service.js进行拆分,把小程序不同界面的js逻辑从app-service.js文件中拆分出来, 各界面打开时再按需加载,减少了首屏加载过程中所需要加载的内容,可缩短首屏展示时间。
如下图所示,拆分前,app-service.js包含拆出来的pageA、pageB、pageC的js逻辑。拆分后,首屏仅需要下载完“瘦身后”的app-service.js以及首页pageA.js再加载即可。
1.4 pkg文件顺序重排优化
为了达到流加载的最大收益,我们还做了【pkg包中文件分布顺序的优化】。
举个例子,如下是某个小程序pkg包文件分布图,从低到高位分别安放着以下文件:
当小程序启动后,pkg下载的大小刚好包含game.js文件,于是小程序开始加载执行game.js, 但game.js中又去加载了gameB.js,这种情况下,小程序就会停止执行,等待pkg继续下载,直到包下载大小超过了gameB.js才会继续执行。
【pkg包内文件分布顺序】的优化就是为去调整文件在pkg包中的坐落位置,尽可能让文件分布顺序与小程序启动执行要加载的文件顺序一致。这样就可以减少在启动无缓存小程序的过程中, 出现要加载某个尚未下载到的文件而停止等待的场景。
后台每日根据上报的文件访问顺序埋点,按顺序以及频率进行排序,优化pkg的文件顺序,生成新的pkg。该操作无需开发者做任何操作。