CacheManager.match(Object evt)

基础库 2.24.0 开始支持,低版本需做兼容处理。

微信小程序插件:不支持

相关文档: 弱网体验优化

功能描述

匹配命中的缓存规则,一般需要和 request 事件搭配使用。

参数

Object evt

request 事件对象

返回值

Object

匹配到的缓存

属性 类型 说明
ruleId string 命中的规则 id
cacheId string 缓存 id
data any 缓存内容,会带有 fromCache 标记,方便开发者区分内容是否来自缓存
createTime number 缓存创建时间
maxAge number 缓存有效时间

示例代码

function handler(evt) {
  const cache = cacheManager.match(evt)
  // 若有重复监听,则取第一个 handler 返回的 promise
  return new Promise((resolve, reject) => {
    if (cache.data) {
      resolve(cache.data)
    } else {
      reject('no cache')
    }
  })
}
cacheManager.on('request', handler)

CacheManager.addRule

基础库 2.24.0 开始支持,低版本需做兼容处理。

微信小程序插件:不支持

相关文档: 弱网体验优化

功能描述

添加规则。

参数

string|RegExp|Record. rule

规则

返回值

string

规则 id

规则说明

支持的规则写法有字符串、正则和对象三种:

字符串写法

  1. addRule('/abc'):纯 uri 串。
  2. `addRule(‘GET /abc’):带方法的 uri 串,除了匹配 uri 外,还会匹配请求方法。如例子中必须是 GET 方法请求才会被匹配。
  3. addRule('/abc/:id'):带可变部分的 uri 串,id 可以是任意符合标准的字符串,表示这一段可以动态变化。比如/abc/123和/abc/321都会被匹配,而/abc/123/xxx` 因为多了一段,就不会被匹配。
  4. addRule('/abc?aa'):带 query 参数的 uri 串,包含 aa 参数,值可以为任意值。比如/abc?aa=haha会被匹配,但是/abc就不会被匹配,因为缺少规则中声明的 aa 参数;不过如果请求是/abc?aa=haha&bb=123`,虽然多带了 bb 参数,但是因为包含了 aa 参数,所以也可以被匹配。
  5. addRule('/abc?dd=haha'):带 query 参数的 uri 串,包含 dd 参数且值为 haha。比如/abc?dd=haha和/abc?dd=haha&bb=123会被匹配,而/abc?dd=123` 就不会被匹配,因为规则要求了 dd 参数的值。

以上写法中的 uri 串如果只有 path 部分,则会取全局 origin 进行补全。比如全局 origin 是 https://weixin.qq.com,而规则是 /abc,则会补全为 https://weixin.qq.com/abc。因此在前面例子中 addRule('/abc') 和 addRule('https://weixin.qq.com/abc') 的写法效果一致。所以一般情况下如果需要匹配的请求 origin 和全局 origin 一致,则规则中可忽略不写 orign。

正则写法

  1. addRule(/\/(abc|cba)$/ig):直接正则匹配请求的 uri,同时会比对请求 origin 和全局 origin 是否一致。
  2. addRule(/^https:\/\/weixin.qq.com\/(abc|cba)$/ig):带有 orign 部分的正则表达式,则只匹配 uri,不再比对 origin。

对象写法

使用规则对象,可以更为详细的描述规则内容。(一般使用规则对象,是为了匹配请求参数)

规则对象:

属性名 类型 默认值 备注
id string 规则 id,如果不填则会由基础库生成
method string 请求方法,可选值 GET/POST/PATCH/PUT/DELETE,如果为空则表示前面提到的所有方法都能被匹配到
url any 必填 uri 匹配规则,可参考规则字符串写法和正则写法
maxAge number 7 * 24 * 60 * 60 * 1000 缓存有效时间,单位为 ms,不填则默认取缓存管理器全局的缓存有效时间
dataSchema Array<DataRule> 匹配请求参数

其中,dataSchema 用来匹配对象类型的请求参数(比如 wx.request 的 data),默认可以不填,即不做参数匹配。

dataSchema 的类型是一个 DataRule 对象数组,一个 DataRule 对象描述一个参数,比如一个 wx.request 请求的 data 是 {a: 123, b: 'haha', c: true},你想要用一条规则来匹配其中的 a 和 b 参数,如果 a 是数字且 b 是字符串就能命中该规则,那么就需要在 dataSchema 中补充两个 DataRule 对象,即 [{name: 'a', schema: {type: 'number'}}, {name: 'b', schema: {type: 'string'}}]。

DataRule 对象:

属性名 类型 默认值 备注
name string 需要匹配的参数名
schema DataSchema/Array<DataSchema> 需要匹配的参数模式,支持数组,表示该参数值有多种模式

name 表示要匹配的参数名,schema 为 DataSchema 对象,用来描述该参数的类型和值。

一个 DataRule 对象也可以匹配可能拥有多种类型的参数,所以 schema 也支持为 DataSchema 对象数组。比如上述例子中,希望匹配的 a 参数必须是数值或者字符串,那么可以这么写:{name: 'a', schema: [{type: 'number'}, {type: 'string'}]}。

DataSchema 对象:

属性名 类型 默认值 备注
type string 需要匹配的 data 对象的参数类型,string、number、boolean、null、object、any(表示任意类型),同时支持数组模式(数组模式则在类型后面加 [],如 string[] 表示字符串数组)
value string/regexp/function/Array<DataRule> 需要匹配的 data 对象的参数值,当 type 为基本类型时,可以用 string/regexp 来匹配固定的值,也可以通过 function 来确定值是否匹配,如果传入的 type 是 object,那么表示需要嵌套匹配值是否正确,可以传入 Array

type 参数表示要匹配的参数类型,value 表示要匹配的参数值。其中 value 支持多种写法,不同写法有如下匹配方式:

  1. 字符串写法:直接判值的字符串形式是否和给定字符串一样,比如 value 值为 123,就要求参数值必须为 123 才能与之匹配。
  2. 正则写法:直接判值的字符串形式是否能被正则匹配,比如 value 值为 /\d+/ig,就要求参数值必须为数字,如果参数值为 abc 则不会被匹配。
  3. 函数写法:在匹配时会调用用户传入的函数,交由用户判断是否匹配。
  4. DataRule 数组写法:当参数类型为对象时,那么字符串写法和正则写法就无法使用,需要传入 DataRule 数组来进行匹配,即通过嵌套 DataRule 数组的方式来匹配嵌套的对象。

示例代码

const ruleId = cacheManager.addRule({
  id: 'haha-rule',
  method: 'GET',
  url: '/haha',
  maxAge: 123455,
  dataSchema: [
    // data 字段的匹配,默认为空,表示不匹配
    // 类型可以是:string、number、boolean、null、object、any(表示任意类型均可),以及这些类型的数组表示方式
    {name: 'aaa', schema: {type: 'string'}}, // 类型为 string
    {name: 'bbb', schema: [{type: 'number'}, {type: 'string'}]}, // 类型为 number, string
    {name: 'ccc', schema: {type: 'string', value: 'abc'}}, // 值为 abc
    {name: 'ddd', schema: {type: 'string', value: /(abc|cba)/ig}}, // 值符合该正则匹配,如果该值不是字符串类型,则会被尝试转成字符串后再进行比较
    {name: 'ddd', schema: {type: 'string', value: val => val === '123'}}, // 传入函数来校验值
    {name: 'eee', schema: {type: 'object', value: [{ // 类型为对象,则通过嵌套的方式来逐层校验
      name: 'aaa', schema: {type: 'string'},
      // ...
      // 嵌套 dataSchema,同上面的方式一样来匹配嵌套的对象
    }]}},
    {name: 'fff', schema: {type: 'string[]'}}, // 类型为 string 数组
    {name: 'ggg', schema: {type: 'any'}}, // 类型为任意类型
    {name: 'hhh', schema: {type: 'any[]'}}, // 类型为任意类型的数组
  }],
})

补充说明

用户可以添加多条规则,每条规则都会去解析网络请求,然后判断是否命中规则。假设有多条规则命中,则取第一条命中的规则。

缓存覆盖

不同的网络请求也可能命中同一条规则,所以每条规则可能对应多个缓存。每条规则会有一个规则 id,每个缓存会有一个缓存 id,一个规则 id 可能对应多个缓存 id,而缓存管理器的缓存存储是基于缓存 id 标识的,如果两个不同的请求生成了同样的缓存 id,那么后发生的请求结果缓存会覆盖前者。因此使用时需要思考缓存的覆盖情况,目前缓存 id 生成方式如下:

  1. 规则使用字符串写法:那么按 method + url + 规则中声明的 query 参数来生成缓存 id。

需要注意的是这里不使用真实请求中的 query 参数来生成缓存 id,而是使用规则中匹配到的 query 来生成缓存 id。比如规则是 /abc?aa=123,请求是 GET 方法的 /abc?aa=123&bb=123,那么就会基于 GET /abc?aa=123 来生成缓存 id。而规则里没有声明 bb=123,所以 bb 参数不会被纳入缓存 id 的生成基准。

  1. 规则使用正则写法:那么只按 method + url 生成缓存 id,不考虑 query 参数。
  2. 规则使用对象写法:如果规则对象中的 url 是字符串写法,那么按 method + url + 规则中声明的 query 参数 + 规则中 dataSchema 声明的请求参数来生成缓存 id;如果规则对象中的 url 是正则写法,那么按 method + url + 规则中 dataSchema 声明的请求参数来生成缓存 id。

生成缓存 id 时没有使用请求中完整的 query 参数或者请求参数来作为基准,是考虑到很多请求可能会带上 token 或时间戳等参数。因为此参数存在不确定性,会导致每次请求生成的缓存 id 都不同,进而导致缓存命中率下降,故采取规则中声明的 query 参数和 dataSchema 声明的请求参数来作为生成缓存 id 的基准。