微信小程序中网络请求缓存的解决方法


Posted in Javascript onDecember 29, 2019

需求

提交小程序审核时,有一个体验测评,产品让我们根据小程序的体验测评报告去优化小程序。

其中有一项是网络请求的优化,给我们出了很大的难题。

文档中是这样解释的:3分钟以内同一个url请求不出现两次回包大于128KB且一模一样的内容

看到这个问题的时候,首先想到的是在响应头上加上cache-control,经过测试发现小程序并不支持网路请求缓存。搜索发现官方明确答复,小程序不支持网络请求缓存:wx.request不支持http缓存

既然官方不支持网络请求缓存,那只能自己想办法解决这个问题了。

先来看一下需求:3分钟内,同一请求只能请求一次。

分析

分析:

  • 只需做GET请求的网络缓存。
  • 缓存时间如何控制。
  • 做了缓存之后,如何知道3分钟,这个请求在服务端数据有没更新。
  • 提交GET请求前,先检查本地有没有缓存

前两点比较好实现,虽然小程序不支持网络请求缓存,但我们还是可以利用cache-control来实现这个功能。

首先网络请求需不需要情缓存统一交给服务端去做,服务端在处理GET请求时,统一加上响应头cache-control,如果需要缓存就用max-age=180,如果不需要做网络请求就用no-cache。前端根据响应头信息自己做前端缓存。

其中的难点是前端如何知道服务端数据有没更新,如果服务端数据更新了,前端还是使用缓存这是有问题的。

经过一番思考后发现,前端提交数据后,相应的GET请求数据会更新,也就是说前端只要有数据提交,就应该把缓存清空。

这有一个难点,当前端提交数据时,前端是不知道哪些GET请求会因此更新数据,所以这个问题我们没有解决,我的方法比较粗暴:只要前端提交了数据,就将所有缓存清空。这是一个治标不治本的问题。

实现

公司项目封装了HTTP请求

拦截请求,如果是GET请求,检查缓存,

  • 如果缓存没过期,将缓存返回出去,不再发请求
  • 如果缓存过期,发请求
if (request.method.toLowerCase() === "get"){
 // param 请求信息
 const cache = this.handleCatchControl(request)
 if (!cache.isRequest)
 return this.listener.onApiResponse(request, 200, cache.data), sequence; //将缓存返回给对应的请求
}

缓存网络请求

// param 响应头,上下文,响应数据
this.setCatchControl(headers, context, response.data)

两个工具函数

  • 处理网络缓存
  • 设置网络缓存

设置网络请求

  1. GET请求缓存数据,其他请求清空数据
  2. 数据格式:
//如果同时发起多个`GET`请求,需要拼接之前缓存数据
ApiAgent.cacheData = Object.assign(ApiAgent.cacheData,{
 [context.request.url]: { //api
 data, //响应数据
 expireTime: Number(cacheControl.split("=")[1] + '000'), //过期时间
 cacheTime: new Date().getTime(), //缓存时间
 }
})
// param 响应头,上下文,响应数据
setCatchControl(responseHeader: any, context: any, data: any) {
 if (context.request.method.toLowerCase() === "get") {
 const headers = HandleHeaders.get(responseHeader)
 const cacheControl = headers["cache-control"]
 if (cacheControl && cacheControl !== "no-cache") {
  ApiAgent.cacheData = Object.assign(ApiAgent.cacheData,{
  [context.request.url]: {
   data,
   expireTime: Number(cacheControl.split("=")[1] + '000'),
   cacheTime: new Date().getTime(),
  }
  })
 }
 } else {
 ApiAgent.cacheData = {}
 }
}

处理网络缓存

  1. 判断缓存是否存在
  2. 判断缓存有没过期,在设置缓存时,比对当前时间和缓存时间,是否小于失效时间
// param 请求信息
handleCatchControl(request): any {
 const cacheArr = ApiAgent.cacheData
 if (Object.keys(cacheArr).length === 0)
 return { isRequest: true }
 let cache = {}
 Object.keys(cacheArr).forEach(cacheArrKey => {
 if (cacheArrKey === request.url) {
  cache = cacheArr[cacheArrKey]
 }
 })
 const newDate = new Date().getTime()
 if (newDate - cache.cacheTime < expireTime){
 return { isRequest: false, data: cache.data }
 }
 return { isRequest: true}
}

响应头全部变成小写,在小程序中,无法确定响应头的大小写会导致报错,所以统一处理响应头

class HandleHeaders {
 static get(headers: { [key: string]: string }) {
 const headersData: any = {}
 Object.keys(headers).forEach(key => {
  headersData[key.toLowerCase()] = headers[key]
 })
 return headersData
 }
}

总结

有一点没有说,就是这个缓存是保存在哪里的?

既没有用localStorage,也没有用globalapp,用的是类的静态属性。

这样做有3个好处:

  1. 使用localStorage数据不好清除,后期可维护性也较差
  2. 缓存挂在globalapp和请求无直接联系
  3. 无需在退出小程序时手动清理缓存

我在使用时遇到一个坑,是因为自己没有理解:类能保存数据的,不能保存状态,但类的对象是既可以保存数据,也可以保存状态的。

最后,此方法还是有很大的优化空间。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
js小技巧--自动隐藏红叉叉
Aug 13 Javascript
基于jquery的direction图片渐变动画效果
May 24 Javascript
capacityFixed 基于jquery的类似于新浪微博新消息提示的定位框
May 24 Javascript
使用Grunt.js管理你项目的应用说明
Apr 24 Javascript
使用insertAfter()方法在现有元素后添加一个新元素
May 28 Javascript
jquery操作复选框checkbox的方法汇总
Feb 05 Javascript
js+html5实现canvas绘制圆形图案的方法
Jun 05 Javascript
jquery验证手机号是否正确实例讲解
Nov 17 Javascript
Vue.js实现一个todo-list的上移下移删除功能
Jun 26 Javascript
用户管理的设计_jquery的ajax实现二级联动效果
Jul 13 jQuery
vuex state及mapState的基础用法详解
Apr 19 Javascript
vue如何在用户要关闭当前网页时弹出提示的实现
May 31 Javascript
vue点击按钮动态创建与删除组件功能
Dec 29 #Javascript
纯js+css实现仿移动端淘宝网站的弹出详情框功能
Dec 29 #Javascript
vue中实现点击按钮滚动到页面对应位置的方法(使用c3平滑属性实现)
Dec 29 #Javascript
vue element-ui实现input输入框金额数字添加千分位
Dec 29 #Javascript
jstree中的checkbox默认选中和隐藏示例代码
Dec 29 #Javascript
Vue组件通信入门之Provide和Inject机制
Dec 29 #Javascript
JS中数组实现代码(倒序遍历数组,数组连接字符串)
Dec 29 #Javascript
You might like
PHP开发入门教程之面向对象
2006/12/05 PHP
把1316这个数表示成两个数的和,其中一个为13的倍数,另一个是11的倍数,求这两个数。
2011/06/24 PHP
php页面跳转代码 输入网址跳转到你定义的页面
2013/03/28 PHP
php 伪静态之IIS篇
2014/06/02 PHP
Thinkphp批量更新数据的方法汇总
2016/06/29 PHP
thinkphp框架使用JWTtoken的方法详解
2019/10/10 PHP
关于javascript function对象那些迷惑分析
2011/10/24 Javascript
js获取当前时间显示在页面上并每秒刷新
2014/12/24 Javascript
javascript实现确定和取消提示框效果
2015/07/10 Javascript
Node.js常用工具之util模块
2017/03/09 Javascript
jquery append与appendTo方法比较
2017/05/24 jQuery
webpack处理 css\less\sass 样式的方法
2017/08/21 Javascript
封装运动框架实战左右与上下滑动的焦点轮播图(实例)
2017/10/17 Javascript
JS实现的文件拖拽上传功能示例
2018/05/21 Javascript
Vue项目中添加锁屏功能实现思路
2018/06/29 Javascript
vue最简单的前后端交互示例详解
2018/10/11 Javascript
js加减乘除精确运算方法实例代码
2021/01/17 Javascript
[03:42]2014DOTA2西雅图国际邀请赛7月9日TOPPLAY
2014/07/09 DOTA
[07:57]2018DOTA2国际邀请赛寻真——PSG.LGD凤凰浴火
2018/08/12 DOTA
17个Python小技巧分享
2015/01/23 Python
Python读取图片属性信息的实现方法
2016/09/11 Python
CentOS 7下安装Python 3.5并与Python2.7兼容并存详解
2017/07/07 Python
对Python中列表和数组的赋值,浅拷贝和深拷贝的实例讲解
2018/06/28 Python
python接口自动化(十六)--参数关联接口后传(详解)
2019/04/16 Python
python跳出双层for循环的解决方法
2019/06/24 Python
Python 保存加载mat格式文件的示例代码
2020/08/04 Python
python 基于pygame实现俄罗斯方块
2021/03/02 Python
印度尼西亚在线时尚购物网站:ZALORA印尼
2016/08/02 全球购物
海蓝之谜(LA MER)澳大利亚官方商城:全球高端奢华护肤品牌
2017/10/27 全球购物
北美主要的汽车零部件零售商:AutoShack.com
2019/02/23 全球购物
幼儿园小班家长寄语
2014/04/02 职场文书
小班上学期评语
2014/05/05 职场文书
办公室主任岗位承诺书
2014/05/29 职场文书
2015年护士医德医风自我评价
2015/03/03 职场文书
小学班级标语口号大全
2015/12/26 职场文书
详细聊聊MySQL中慢SQL优化的方向
2021/08/30 MySQL