需求
提交⼩程序审核时,有⼀个体验测评,产品让我们根据⼩程序的体验测评报告去优化⼩程序。
其中有⼀项是⽹络请求的优化,给我们出了很⼤的难题。
⽂档中是这样解释的: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 (LowerCase() === "get"){
// param 请求信息
const cache = this.handleCatchControl(request)
if (!cache.isRequest)
return ApiResponse(request, 200, cache.data), sequence; //将缓存返回给对应的请求
}
缓存⽹络请求
// param 响应头,上下⽂,响应数据
this.setCatchControl(headers, context, response.data)
两个⼯具函数
处理⽹络缓存
设置⽹络缓存
设置⽹络请求
1. GET请求缓存数据,其他请求清空数据
2. 数据格式:
//如果同时发起多个`GET`请求,需要拼接之前缓存数据
ApiAgent.cacheData = Object.assign(ApiAgent.cacheData,{
[quest.url]: { //api
data, //响应数据
expireTime: Number(cacheControl.split("=")[1] + '000'), //过期时间
cacheTime: new Date().getTime(), //缓存时间
}
})
// param 响应头,上下⽂,响应数据
setCatchControl(responseHeader: any, context: any, data: any) {
if (LowerCase() === "get") {
const headers = (responseHeader)
const cacheControl = headers["cache-control"]
if (cacheControl && cacheControl !== "no-cache") {
ApiAgent.cacheData = Object.assign(ApiAgent.cacheData,{
[quest.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 => {
LowerCase()] = headers[key]
})
return headersData
}
}
总结
有⼀点没有说,就是这个缓存是保存在哪⾥的?
既没有⽤localStorage,也没有⽤globalapp,⽤的是类的静态属性。
这样做有3个好处:
1. 使⽤localStorage数据不好清除,后期可维护性也较差
2. 缓存挂在globalapp和请求⽆直接联系
3. ⽆需在退出⼩程序时⼿动清理缓存
我在使⽤时遇到⼀个坑,是因为⾃⼰没有理解:类能保存数据的,不能保存状态,但类的对象是既可以保存数据,也可以保存状态的。
最后,此⽅法还是有很⼤的优化空间。
好了,以上就是这篇⽂章的全部内容了,希望本⽂的内容对⼤家的学习或者⼯作具有⼀定的参考学习价值,谢谢⼤家对的⽀持。
发布评论