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


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 相关文章推荐
基于jquery的jqDnR拖拽溢出的修改
Feb 12 Javascript
33个优秀的 jQuery 图片展示插件分享
Mar 14 Javascript
Javascript弹出窗口的各种方法总结
Nov 11 Javascript
使用jquery菜单插件HoverTree仿京东无限级菜单
Dec 18 Javascript
jquery拖拽排序简单实现方法(效果增强版)
Feb 16 Javascript
jQuery控制li上下循环滚动插件用法实例(附demo源码下载)
May 28 Javascript
jquery自动补齐功能插件flexselect用法示例
Aug 06 Javascript
基于JavaScript实现百度搜索框效果
Jun 28 Javascript
BootStrap表单验证中的非Submit类型按钮点击时触发验证的坑
Sep 05 Javascript
Vue实现将数据库中带html标签的内容输出(原始HTML(Raw HTML))
Oct 28 Javascript
JQuery通过键盘控制键盘按下与松开触发事件
Aug 07 jQuery
vue中axios封装使用的完整教程
Mar 03 Vue.js
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 设计模式之 单例模式
2008/12/19 PHP
PHP函数preg_match_all正则表达式的基本使用详细解析
2013/08/31 PHP
PHP中list方法用法示例
2016/12/01 PHP
Thinkphp开发--集成极光推送
2017/09/15 PHP
php基于协程实现异步的方法分析
2019/07/17 PHP
PhpStorm 如何优雅的调试Hyperf的方法步骤
2019/11/24 PHP
window.name代替cookie的实现代码
2010/11/28 Javascript
基于Jquery的仿照flash放大图片效果代码
2011/03/16 Javascript
jquery实现可拖动DIV自定义保存到数据的实例
2013/11/20 Javascript
jquery设置text的值示例(设置文本框 DIV 表单值)
2014/01/06 Javascript
jquery的ajax和getJson跨域获取json数据的实现方法
2014/02/04 Javascript
Javascript 多物体运动的实现
2014/12/24 Javascript
理解JavaScript的变量的入门教程
2015/07/07 Javascript
基于javascript实现单选及多选的向右和向左移动实例
2015/07/25 Javascript
js实现左侧网页tab滑动门效果代码
2015/09/06 Javascript
详解JavaScript基于面向对象之创建对象(1)
2015/12/10 Javascript
jQuery实现图片轮播效果代码
2016/09/27 Javascript
jq.ajax+php+mysql实现关键字模糊查询(示例讲解)
2018/01/02 Javascript
在vue中使用jointjs的方法
2018/03/24 Javascript
详解Ant Design of React的安装和使用方法
2018/12/27 Javascript
[01:09:10]NB vs Liquid Supermajor小组赛 A组胜者组决赛 BO3 第一场 6.2
2018/06/04 DOTA
详谈python3中用for循环删除列表中元素的坑
2018/04/19 Python
python 移除字符串尾部的数字方法
2018/07/17 Python
python psutil模块使用方法解析
2019/08/01 Python
深入浅析Python科学计算库Scipy及安装步骤
2019/10/12 Python
TensorFlow——Checkpoint为模型添加检查点的实例
2020/01/21 Python
django model的update时auto_now不被更新的原因及解决方式
2020/04/01 Python
通信工程毕业生自荐信
2013/11/01 职场文书
计算机售后服务承诺书
2014/05/30 职场文书
乡镇精神文明建设汇报材料
2014/08/15 职场文书
2014年大学团支部工作总结
2014/12/02 职场文书
先进事迹材料怎么写
2014/12/30 职场文书
2015年大班保育员工作总结
2015/05/18 职场文书
2015年小学图书室工作总结
2015/05/18 职场文书
电工生产实习心得体会
2016/01/22 职场文书
Vue实现跑马灯样式文字横向滚动
2021/11/23 Vue.js