关注专题不迷路,进入“开发技术新风向”专题首页,点击“关注”即可
更多视频版本请前往学堂收看《如何用性能分解读小程序》
一、什么是数据预取
数据预取能够在小程序冷启动时提前发起请求,并缓存请求内容,在真实请求时使用缓存数据,减少网络请求的时间。在一些发起网络请求较晚的场景,增加数据预取,可以提升页面完全展现的速度。
- 数据预取优势说明:
是否有预取 | 请求时机 | 备注 |
没有预取 | 启动后串行发起请求 | 网络请求会较晚 |
有预取 | 启动时并行发起请求 | 尽可能将请求时间提前 |
- 预取注意事项:
预取只是一个提取执行请求的附加优化方案,预取逻辑和小程序启动逻辑是并行启动的,在正常接入数据预取并且能够命中缓存的情况下,不会对服务器造成额外负担。
标题 | 二级标题 | 内容 |
预取KEY | 不带参数 | id和url不带query部分相同时认为是同一个请求 |
不带参数,id相同 | 非预取发起的两个请求url如果不带query部分和 + id参数都相同时,也认为是同一个请求,如果传了usePrefetchCache,第二次请求会命中第一次的缓存 | |
更新缓存 | usePrefetchCache为false | 只传入id,usePrefetchCache不传入或者未false时,会更新缓存。 |
有效期 | 缓存有效期为5min,app重启后销毁。 | |
性能 | 重复请求 | 预取的请求和小程序实际的请求一致,否则会引入额外请求 |
LCP后的请求 | 只预取LCP前的关键请求,否则性能可能会恶劣 | |
JS文件大小 | 尽量减少prelaunch.js的体积,建议小于10k | |
其他 | - | 需要保证prelaunch.js未执行会或者执行失败时,逻辑能正常运行 |
二、新、老方案的区别是什么
老方案指的是配置方案,可以通过配置的方式配置预取的内容。
但是当逻辑比较复杂,比如需要登录之后再预取,那配置方案就无法实现了。此时就有了可以通过js代码来编写预取的方式。
- | 新方案(JS方案) | |
原理 | 通过json配置,客户端解析配置处理 | 独立js环境,开发者通过js控制要执行的逻辑 |
能力 |
|
|
接入成本 | 略高,整体链路对开发者黑盒,不便调试 | 低,便于调试,支持打印log |
适用场景 | 参数简单,n个独立请求的简单场景。 | 配置方案不满足的复杂场景 |
三、详细使用教程:
开始前,下载最新版本 IDE 调试工具(4.2.4 或以上版本)
Web 页面 LCP 的优秀值为 2500ms,为减少因为性能问题导致的用户流失,我们目标设置为 2000ms。
第一步:明确优化页面目标
选取PV较高的作为重点优化对象(不确定的可以通过「控制台-数据-数据中心-页面分析」模块查看)。
将PV 较高的页面设置为启动页面(如右图),然后进行第二步。
第二步:找出影响启动 / 页面切换耗时的主要影响元素
1、在IDE 中使用“体验评分工具” 勾选真机体验后,运行待整个页面渲染完成,点击屏幕后停止(点击屏幕是为了触发LCP 上报)。
2、查看体验评分结果(右图),截图部分为当前场景的最大元素,就是主要优化对象。
3、找到主要优化目标:
- 目标一:影响该部分渲染的数据请求(数据来源 、展示时机等),为主要优化接口,进行第三步「预取主要接口」。
第三步:预取主要数据接口
1、优化思路:尽可能前置主要元素的渲染时机
2、预取逻辑:
- 根据上述流程找到 LCP 触发元素(上右图 已经圈⭕️出来了!),如果是图片,直接预取该图片。
- 点击「查看详情」(下左图)展开渲染层,可以看到图片渲染时机。
- 点击「查看详情」展开网络层,找到影响 LCP 元素的网络请求,选中看url 信息确认是不是LCP元素的数据源。
- 找到重要请求后,尽可能前置请求发出的时机,依次检查以下几点:
- 有前置依赖请求:对前置依赖配置预取,否则直接预取该请求,参考接入示例代码
- 请求发起时机较晚(trace中请求前有其他逻辑或在 onload 之后):尽早早早发出该请求,并及时更新数据。
- 有前置同步 API:尽可能替换为异步API,或者放在请求后。
四、常见问题:
(1)业务接口依赖 tt.login 无法直接预取
新的数据预取方案 prelaunch.js 支持 tt.login 等API,具体支持范围见数据预取js方案-预取环境中支持的API。如有其他需求,可以直接通过社区、开发者助手等方式反馈。
(2)业务接口参数需要 md5 签名
使用三方框架开发的小程序, prelaunch.js 因为不支持原生打包,所以普通开发者如果使用到crypto-js时不知道如何处理。这里暂时提供一段精简后的crypto-js代码(只包含md5 / HmacMD5,core),详情请查看:数据预取js方案。
(3)业务接口依赖启动场景值
新的预取方案支持在 prelaunch.js 中调用 tt.getLaunchOptionsSync,可以通过该API 直接获取启动参数。
(4)部分场景不希望命中预取结果
数据预取js方案中,本次请求不命中预取结果,可以将 usePrefetchCache 设置为 false, 或者调整 id 为未预取过的请求。
示例场景:希望详情接口只在页面A 使用缓存,其他页面发起请求时不希望命中预取。
示例建议:配置预取时,id 命名为 ${字符串}_${页面path} 作为标识。
(5)预取了很多接口,为什么优化不明显
数据预取的接口或图片并不是越多越好,目标是将重点请求接入预取(如LCP 的触发元素或其来源请求)
数据预取只是将请求前置,预取时发起过多请求也会有资源竞争,可能导致预取耗时过长,预取结果命中率降低。
建议接入个数:1~3 个(接口 或 图片数量,分开计数);
分析步骤:见启动性能优化指引。
(6)数据预取的请求会阻塞后面的请求吗? 相同的请求,如果预取没有请求完毕,会发起两遍吗
数据预取不会阻塞,是并行的状态,后续相同的请求,会使用之前请求的结果。
不会发起两遍,如果调用 tt.request 时请求时传入的 id 参数相同,那么第二个请求不会发起网络请求,会直接复用第一次请求。
(7)prelaunch.js 执行时机是什么时候,和请求前置到 onLaunch 效果一样么
prelaunch 效果更好,onLaunch 阶段任务更多,API 调用可能会被阻塞,prelaunch 的执行是在一个独立的线程,效率更高。
(8)数据预取链接失败,捞日志发现timeout
可能原因有:
手机和电脑不在同一个局域网。
电脑打开了防火墙,导致手机无法访问,关闭后正常,可以在手机上直接访问 ip:7047 看是否能通。
(9)如何在 prelaunch.js 中使用环境变量
可以通过字符串替换的方式来注入环境变量
(10)「registerOnPrelaunch 的回调在小程序生命周期只会触发一次」,启动页面A 和 app 都注册了,两个回调都会触发吗?
通过 registerOnPrelaunch 注册的 app 和 特定页面的回调,都会执行, app 先执行。
(11)数据预取js 方案和配置方案可以一起使用么
不建议一起用,两者效果相同,只保留一种就可以。因为数据预取js 方案是一个独立的 worker 环境,请求链路无法复用,两个预取请求都会发出,导致不必要的资源浪费。
