# 弱网体验优化

在用户使用小程序时,可能会陷入某些网络不通畅的场景,此时一些严格依赖网络的功能可能就无法使用。为此我们计划提供一些措施来协助开发者优化弱网时小程序的使用体验。

目前,以下依赖网络的功能可以通过接入缓存管理器改善:

  • 纯展示类的功能
  • 只依赖部分用户授权的功能

# 缓存管理器

注意:目前暂时只有 iOS 端支持

小程序提供了一个无侵入式的缓存管理器,开发者可以不需要修改原有业务代码进行接入。缓存管理器主要有以下几个能力:

  • 在网络通畅时,对符合规则的网络请求进行缓存;在弱网时对该网络请求使用缓存返回。
  • 在网络通畅时,对部分 wx api 调用进行缓存;在弱网时对这些 wx api 的调用使用缓存返回。

简单来说,缓存管理器可以帮助开发者在不修改小程序主要逻辑的情况下,快速接入缓存能力。接入过程只需要额外编写如下几行代码:

// 创建缓存管理器
const cacheManager = wx.createCacheManager({
  origin: 'https://weixin.qq.com/',
})

// 添加请求规则
cacheManager.addRules([
  '/cgi/home',
  '/cgi/detail/:id',
])

// 监听符合规则的 wx.request 请求,默认在弱网时调用 wx.request 即会触发
cacheManager.on('request', evt => {
  return new Promise((resolve, reject) => {
    // 匹配是否存在缓存
    const matchRes = cacheManager.match(evt)

    if (matchRes && matchRes.data) {
      // 使用缓存返回
      resolve(matchRes.data)
    } else {
      // 没有匹配到缓存
      reject({errMsg: `catch not found: ${evt.url}`})
    }
  })
})

上述示例中使用 wx.createCacheManager 即可创建缓存管理器。缓存管理器全局只有唯一实例,一旦被成功创建出来即表示接入成功。

开发者需要添加请求规则,用来匹配哪些请求需要被缓存,不在请求规则内的请求会被自动放过。一旦请求命中规则,则在网络通畅时会对结果进行缓存,在弱网时会拦截请求,然后触发 request 事件给开发者。开发者可以在事件回调中决定是否使用缓存返回,如果使用缓存返回,则不会再发起网络请求;如果仍要尝试发起网络请求,可像如下方式操作:

cacheManager.on('request', async evt => {
  try {
    // 仍然走网络请求
    const res = await evt.request()
    
    // ......
  } catch (err) {
    // ......
  }
})

为了适应更多的请求场景,请求规则支持多种写法,如:

cacheManager.addRule('/abc') // uri 串,会自动使用调用 wx.createCacheManager 时传入的 origin 进行拼接,然后匹配
cacheManager.addRule('GET /abc') // 在 uri 串基础上,补充请求方法的匹配
cacheManager.addRule('/abc/:id') // 带可变部分的 uri 串

cacheManager.addRule(/\/(abc|cba)$/ig) // 正则表达式

cacheManager.addRule({
  method: 'POST',
  url: '/abc',
  dataSchema: [
    {name: 'param1', schema: {value: /(aaa|bbb)/ig}},
    {name: 'param2', schema: {value: '123'}},
  ],
}) // 规则对象

更多规则写法可参考 addRule 文档

每个命中了规则的请求,会根据一定策略生成缓存 id,如果两个请求生成的缓存 id 相同,则后者会覆盖前者,因此在编写规则时需要注意这点。一般来说,请求 url 不同或请求方法不同,生成的缓存 id 一定不同;如果请求参数不同,则需要考虑命中的规则有没有考虑参数的情况,详细的缓存 id 生成策略可参考 addRule 文档

缓存存储会使用独立的用户空间(不占用用户的 storage),不过有缓存数量和大小限制,所以也不要无节制地使用缓存。请善用规则,尽可能只让必要的请求缓存。

关于缓存管理器的详细使用方式可参考 api 文档。此处同时提供一个完整可运行的例子,参考例子的 README 进行操作即可体验。

# 云托管使用 cacheManager

通过 wx.cloud.callContainer 调用的接口也可以使用 wx.createCacheManager 进行弱网体验优化。缓存请求需要开发者调用 addRule 添加规则。 这里对于 addRule 参数中的 url 字段有个统一规范:https://wx.cloud.callContainer/env/servicename/path ,其中 env / servicename / path 对应 wx.cloud.callContainer 调用服务的标识字段。比如对于如下的云调用,可以按示例添加缓存规则:

const res = await wx.cloud.callContainer({
    config: {
      env: 'test-123'
    },
    path: '/api/count',
    header: {
      'X-WX-SERVICE': 'express-server',
      'content-type': 'application/json'
    },
    method: 'GET',
    data: {
      action: 'inc'
    },
})

// 添加缓存规则
cacheManager.addRule({
    url: 'https://wx.cloud.callContainer/test-123/express-server/api/count',
    method: 'get'
})

# 其他

部分 wx api 在接入缓存管理器后也会进行缓存,列表可参考 wx.createCacheManager 文档,开发者也可以自行调整哪些 wx api 需要缓存。

需要注意的是,如 wx.loginwx.checkSession 等接口支持缓存不等价于该接口在弱网时是可用的,缓存只是将上次成功调用的结果进行返回,接口本身的逻辑并不会改动,也就是说缓存返回中如 code 等有时效限制的内容并不会被刷新,仍然会失效。此处的缓存仅为了减少部分场景的改造成本而提供。

其他部分需要用户授权的接口/组件则会在基础库层面支持在弱网使用,用法与之前一样,开发者无需改造。