必看!揭秘抖音小程序性能提升之流加载

avatar
@字节跳动

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

作者:抖音小程序iOS团队同学

一、流加载是什么?

用一句话来解释流加载,那就是“下载程序包的同时加载包内的文件”,下载与加载并发可以加速小程序首次无缓存启动的时间。

二、实现方案

1.1 使用pkg包替代zip包

流加载方案之前,小程序的文件都是压缩到zip包内的,尽管zip包的体积更小,但zip包内的文件需要等完整的zip包下载好后才能解压出来使用,解压也需要时间。

流加载方案中,我们改用pkg包来装载小程序的文件,pkg包是未压缩过的二进制文件包,可以直接读取包内指定区域的二进制数据。pkg包相比于压缩的zip包体积会更大,通过开启CDN智能压缩服务,在pkg包请求过程中,服务器对返回的pkg数据进行gzip编码,压缩重复的字符串等,可以减少pkg包的传输大小,从而缩短下载时间。

下图可见pkg包内的文件分布结构,仅举例,不同的小程序文件顺序可能不同。 image.png

1. | 文件标识符"PKG"(8字节) | 文件版本号(8字节) |
2. | 扩展信息长度(8字节) | 扩展信息 |
3. | 所包含的文件数量(8字节)|
4. | 文件 1 文件名长度(2字节) | 文件 1 文件名 | 文件 1 偏移量(4字节) | 文件 1 大小(4字节) |
5. | 文件 2 文件名长度(2字节) | 文件 2 文件名 | 文件 2 偏移量(4字节) | 文件 2 大小(4字节) |
6. | ... |
7. | 文件 1 二进制内容 | 文件 2 二进制内容 | ...|

1.2 资源加载时机提前

在pkg格式程序包的支持下,我们不必等待包下载完成后才去加载资源,资源加载的时机得以提前。

流加载优化前后的启动阶段流程分别如下: image.png

image.png

假设某个版本的小程序A在改造前后包内文件不变,资源加载顺序相同,提前加载文件可以使得小程序首屏渲染更快出现。

1.3 小程序包体改造优化

包体改造主要是优化小程序的首屏加载时间,把app-service.js进行拆分,把小程序不同界面的js逻辑从app-service.js文件中拆分出来, 各界面打开时再按需加载,减少了首屏加载过程中所需要加载的内容,可缩短首屏展示时间。

如下图所示,拆分前,app-service.js包含拆出来的pageA、pageB、pageC的js逻辑。拆分后,首屏仅需要下载完“瘦身后”的app-service.js以及首页pageA.js再加载即可。 image.png

1.4 pkg文件顺序重排优化

为了达到流加载的最大收益,我们还做了pkg包中文件分布顺序的优化

举个例子,如下是某个小程序pkg包文件分布图,从低到高位分别安放着以下文件: image.png

当小程序启动后,pkg下载的大小刚好包含game.js文件,于是小程序开始加载执行game.js, 但game.js中又去加载了gameB.js,这种情况下,小程序就会停止执行,等待pkg继续下载,直到包下载大小超过了gameB.js才会继续执行。

pkg包内文件分布顺序的优化就是为去调整文件在pkg包中的坐落位置,尽可能让文件分布顺序与小程序启动执行要加载的文件顺序一致。这样就可以减少在启动无缓存小程序的过程中, 出现要加载某个尚未下载到的文件而停止等待的场景。

后台每日根据上报的文件访问顺序埋点,按顺序以及频率进行排序,优化pkg的文件顺序,生成新的pkg。该操作无需开发者做任何操作。