开发 框架 首屏数据预取
前端框架:1.31.0
客户端版本:10.7.20及以上
# 简介
更新时间:2024-02-04 18:14:32
本功能升级可提升小程序冷启时启动页的加载速度,进而提升用户留存率。
根据平台内测数据显示:Android 设备加载速度提升30%,约为0.5秒;iOS 设备加载速度提升36%,约为0.4秒。
# 升级流程
针对已有的小程序,本次升级共有『三个改动点』,如图中绿色部分所示,可以同步进行。
# 升级前评估
本次升级需要同时满足以下条件:
- 网络请求应为GET方式
- 网络请求需可复用,即网络请求没有参数用于校验重复请求,比如签名参数、用户登录态参数、数据加密参数等
- 如有动态参数,需从启动schema中提取
- 不能强依赖需用户实时授予的权限信息,比如地理位置数据、账户信息等
只支持单独网络请求的预拉取,不支持存在依赖关系的后续网络请求场景(比如请求B的参数依赖于请求A的返回结果,可配置请求A的预拉取能力,B请求不支持)
# 启动页选择
选择需要升级的启动页面和关键网络请求筛选,选择标准如下:
- 启动页面:选取小程序uv/pv量级较大的页面,或运营推广的页面,比如视频播放页、内容详情页
- 关键网络请求:没有前置依赖,并且数据返回直接影响页面有效内容开始渲染的网络请求,例如详情页的视频详情/内容详情接口
# 开发
# (1) app.json配置
在app.json中增加prefetchRules配置项,示例和说明如下:
// app.json
{
"prefetchRules": {
"pages/index/index": { //需要配置预拉取请求的页面,注意:每个页面配置的预拉取请求数量最多为5个
"https://developer.***.com/${search}?a=${a}&b=2&c=3": {//请求的url模型
"method": "GET",//请求的方法,只支持GET
"header": { //请求的header
"a": "${a}",
"token": 1
},
"dataType": "json",//返回结果的类型
"responseType": "text",//返回结果的类型
"hitPrefetchExtraRules": { // 模糊匹配规则,只要包含以下key,并且key对应的值相等就算命中
"requiredQueryKeys": ["a", "b", "c"], // 不考虑顺序
"requiredHeaderKeys": ["a", "token"]
}
},
//...
}
}
}
接下来会有三种情况,需要大家根据技术实现方式做对应的升级。
# (1.1) 如果关键网络请求参数数量较少,并且固定
无需额外操作
# (1.2) 如果关键网络请求存在动态参数
如果动态参数需要从启动的schema中提取,需组装预拉取网络请求数据,包含“配置变量”和“数据填充”两项内容
配置变量
- 为了使配置的请求具有一定的动态能力,引入了“配置变量”的概念,即配置中格式为 ${XXX} 的部分,其中XXX是变量的名称,可以根据此名称对变量赋值,即将${XXX}执行字符串替换的过程,替换的字符串就是变量实际的值。
- 配置变量的限制条件
生效范围
- 请求URL中的 path 和 query 部分,不包含host。第一个配置变量与host之间至少有一个 “/” 或 “?” 间隔(即query、path与host之间有合法的分隔字符
- header 参数
配置变量值的数据源:schema 中 pagePath 的 query(query中path的值实际是一个URL,将此URL解析,读取其query),示例:
// pagePath=pages/index/index?search=searchApp 小程序打开时的协议带有这个search参数,search 的值为searchApp
//赋值前
{
"prefetchRules": {
"pages/index/index": {
"https://developer.****.com/${search}?a=${a}&b=2&c=3": {
"method": "GET",
"header": {
"token": 1
},
"responseType": "",
},
},
//...
}
}
//赋值后
{
"prefetchRules": {
"pages/index/index": {
"https://developer.****.com/searchApp?a=1&b=2&c=3": {
"method": "GET",
"header": {
"token": 1
},
"responseType": "",
},
},
//...
}
}
数据填充
- 配置项中的 method、header、responseType、dataType 和 request API 的各项参数含义基本保持一致
- url 中参数处理逻辑与 request 接口保持一致
- 参数默认值:
参数名 | 数据类型 | 是否必传 | 默认值 | 说明 |
---|---|---|---|---|
header | object | optional | {'content-type': 'application/json'} | 请求 header |
method | string | optional | GET | 请求方法,当前仅支持GET |
dataType | string | optional | json | 数据类型,默认值为json,执行json parse |
responseType | string | optional | text | 响应数据类型,可选值:text |
# (1.3) 如果关键网络请求参数数量较多,存在非必需参数
当请求参数数量较多时,并存在非必需参数时,预拉取请求和后续request请求参数可能不完全一致,可能存在缓存数据命中率不高的问题,需要配置缓存命中规则。
预拉取数据缓存是否命中存在两种匹配规则判断:严格精准匹配、模糊匹配,默认为严格精准匹配。
严格精准匹配
匹配每一个配置参数,只有所有参数完全一致时认为命中缓存,参数包括:
- host
- path
- query
- method
- header
模糊匹配
由于参数可能较多,业务需求有动态变更的需求,严格精准匹配的缓存命中率可能较低,此时可以使用模糊匹配规则,要求必须存在 hitPrefetchExtraRules 配置项,不存在时退化为严格精准匹配。
// app.json
{
"prefetchRules": {
"pages/index/index": {
"https://developer.****.com/${search}?a=${a}&b=2&c=3": {
//...
"hitPrefetchExtraRules": {
"requiredQueryKeys": ["a", "b", "c"],
"requiredHeaderKeys": ["a", "token"]
}
},
//...
},
//...
}
}
对照上面示例,hitPrefetchExtraRules 的规则为:
- 规则为一个 Map,存在两个 Key:requiredQueryKeys、requiredHeaderKeys,分别对应 query 和 header 的模糊匹配规则,如果 Key 不存在,命中的规则为相应部分的严格精准匹配
- requiredQueryKeys 和 requiredHeaderKeys 的值均为一个字符串数组,且不可为空,空数组和 Key 不存在处理方式一致。
- 在对比 query 和 header 时,如果对应的 requiredKeys 规则存在,那么只会比较 requiredKeys 数组中存在的 Key 和 Key 对应的 value 是否相等,其他值不做比较。
举例:
// 预拉取请求
"https://developer.****.com/search?a=1&b=2&c=3"
// 命中规则
{ "requiredQueryKeys": ["a", "b", "c"] }
// request 请求
// 命中
"https://developer.****.com/search?a=1&b=2&c=3&d=4"
// 不命中,c的值不相等
"https://developer.****.com/search?a=1&b=2&c=4"
// 不命中,缺少c
"https://developer.****.com/search?a=1&b=2&d=4"
// *******************
// 预拉取请求
"https://developer.****.com/search?a=1&b=2&c=3":{
header:{a:1,b:2,c:3}
}
// 命中规则
{ "requiredHeaderKeys": ["a", "c"] }
// request 请求
// 不命中,query严格匹配,多了d
"https://developer.****.com/search?a=1&b=2&c=3&d=4"
// 命中,b是不影响判断的key
"https://developer.****.com/search?a=1&b=2&c=3":{
header:{a:1,b:5,c:3}
}
// 不命中,a的值不一致,且缺少c
"https://developer.****.com/search?a=1&b=2&c=3":{
header:{a:3,b:2}
}
# (2) request API 适配
参数变更如下:
- 接口新增 usePrefetchCache 参数,类型为 bool,可选,默认为 false,值为 true 时表示该请求需要使用预拉取的缓存
- 返回数据新增两个字段:
- isPrefetch:区分数据是否为预拉取,类型为 bool ,值为 true 时表示该请求使用了预拉取的缓存
- prefetchInfo:key-value 键值对,用于在预拉取未生效时提供对应信息。当前字段为:
- message:中间过程的信息,类型为字符串
序号 | 情景 | message |
---|---|---|
1 | 请求参数 usePrefetchCache 为 false | prefetch not work because usePrefetchCache = false |
2 | 平台管控导致 prefetch 不生效 | current app network prefetch is disabled |
3 | 当前 request 找不到匹配的可用 prefetch 配置(可能是 app.json 中 prefetchRule 有问题,或者找不到pagePath、url 等匹配的配置等情况) | request url has no prefetch config |
4 | usePrefetchCache 为 true,有 prefetch 配置,但是因为 prefetch 请求发生错误,没有可用的prefetch 缓存 | request url matching prefetch cache is invalid because of error: ERROR_MSG (可以是框架返回的error信息) |
5 | usePrefetchCache 为 true,有 prefetch 配置,但是因为请求没有完全匹配,没有可用的 prefetch 缓存 | request url has no matching prefetch cache |
示例:
//开发者配置app.json
{
"prefetchRules":{
"pages/index/index": {
"https://developer1.****.com/${sid}?testid=${testid}&testdata=${testdata}":{
"method": "GET",
"header": {
"token": "xxxs1823730"
},
"responseType": "",
"hitPrefetchExtraRules": {
"requiredQueryKeys": ["testid", "testdata"],
"requiredHeaderKeys": ["token"]
}
}
//...
}
//...
}
}
//request
ks.request({
url: "https://developer1.****.com/${option.query.sid}?testid=${option.query.testid}&testdata=${option.query.testdata}",
header: {"token":"xxxs1823730"},
method: "GET",
dataType: "json",
responseType: "text",
usePrefetchCache: true,
success: (res) => {
console.log("返回数据是否来自预拉取:", res.isPrefetch);
console.log("预拉取提示信息:", res.prefetchInfo);
console.log("请求数据:", res.data);
},
});
# (3) 性能打点上报
为了更好地评估首屏数据加速的效果,框架新增了 FMP(First Meaningful Paint 是指页面的首要内容出现在屏幕上的时间)性能打点上报 API,开发者需根据业务实际情况以及 FMP 含义,在合适的位置调用。
支持版本:前端框架1.32.1(发布时间:2022.6.20);快手客户端版本:10.7.10(发布时间:2022.8.10)
代码示例:
var performance = ks.getPerformance()
performance.mark('fmp');
# FAQ
1 如果启动首页的路径为空,首屏页面数据加速会生效吗?
如果启动首页的路径为空,会进入配置的默认入口页,如果预拉取的配置中有默认入口页的配置并且满足条件,会触发该页面的预拉取行为。
2 首屏页面数据加速支持 POST 请求吗?
目前暂不支持
3 接入时遇到问题,怎么寻求支持?
建议在 开发者社区 (opens new window) 上发帖咨询,我们收到后会第一时间处理。
4 调试时 vConsole 中没有日志,应该如何处理?
有时日志输出有可能会存在一定的延迟,可以手动关闭 vConsole 后再打开尝试
5 按照文档配置后,调试时打印日志显示没有成功,应该如何排查?
可以按照如下步骤依次检查
- 检查是否为冷启动:首屏数据加速只会在冷启动场景生效
- 检查使用设备是否为商店最新版本
- 检查调试时启动路径和 app.json 中配置是否一致
- 检查$符号后的配置变量名称在启动的 schema 参数中是否存在
- 检查prefetchRules中的对应请求中,header的contentp-type: application/json,以及dataType: json、responseType: text 此类字段是否合理配置。
- 检查 hitPrefetchExtraRules 的 requiredQueryKey、requiredHeaderKeys 是否符合要求
- 以上步骤均已尝试后,依然没有成功,可以将打印日志截屏并提供体验包二维码寻求技术支持。
6 小程序使用了 uniapp 的技术方案开发,可以接入吗?
可以接入,但由于 uniapp 方案会在编译生成的工程中,自动构建 app.json 配置,因此需要按照如下步骤操作:
- 在 JS 代码中,给首屏关键网络请求对应的 request API 调用增加 usePrefetchCache=true 参数以及打印 response 的 isPrefetch、prefetchInfo 信息
- 使用 uniapp 编译得到可以在快手小程序开发者工具中运行的工程,手动修改 app.json 文件,增加 prefetchRules 配置
- 使用真机调试,通过vConsole观察打印的调试信息,遇到问题时可以按照 FAQ 第5条的方式操作
- 调试通过后,删除调试相关代码,重新使用uniapp编译,然后手动修改一下 app.json ,增加上面调通的 prefetchRules 配置。考虑到每次发版都需手动修改较为麻烦,自动修改的方案可以参考 uniapp发行时动态修改manifest.json参数 (opens new window) 的思路
- 把已经修改app.json后的工程打包提审