需求分析
有时候我们从服务器请求到的部分数据在一定时间内是不会变化的,此时重复请求不仅浪费带宽,在网络状态波动时也会降低体验。所以我们希望把这部分数据缓存在本地,当手动清除或过期后再向服务器请求。
概念详解
Promise详解
localStorage详解
简单总结:
- localStorage就是一个可以存储键值对的Map,key、value均限制为String类型,因此我们存储对象时需要用JSON.stringify将其转换为Json字符串,取出对象时需要用JSON.parse将字符串解析为Json对象。
- Promise对象在构造时调用resolve方法可以向回调函数传递对象,而Promise对象使用 .then(res=>{})定义回调函数时,可以拿到resolve传递过来的对象;可以保证前面的耗时操作完成时再执行后续操作(阻塞)。
- 我们可以发现axios也会有.then方法,所以其实它也是返回的一个Promise对象。
需求解析
localStorage的key为String类型,我们需要保证它的唯一性的同时,还要保证查询的时候能够找到。本例中我使用这样一个方法来生成key,可以直接把用于请求的参数对象传入作为key使用(注:有时字段传递数字和只有数字的字符串时会得到相同的响应结果,但是使用此方法会生成不同的key):
let getCacheKey = function (prefix, json) {
return prefix + " " + JSON.stringify(json);
}
由于localStorage对象并不自带过期功能,所以我们不仅需要存储数据,还要存储一个时间戳来验证它是否过期(同时需要给用户提供手动清除缓存的功能)。
本例中在数据key之后拼接一个"Expires"来作为时间戳的key。
核心逻辑
需要传入的参数:
- key
- 过期时长
- 当缓存中没有数据时,执行获取数据的方法
- 上述方法执行时所需要的参数(不定长)
操作流程:
- 尝试从localStorage中取出数据和时间戳,如果数据存在且在有效期内,直接返回该数据
- 如果数据不存在或者已过期,则执行获取数据的方法,在获得数据之后把数据存储到localStorage中、更新时间戳并返回该数据
注:我们发现获取数据的方法可能是耗时的,因此在定义该方法时需要返回一个Promise对象以调用它的回调函数来获取数据。例如:
let requestMethod = function(url,json){
return new Promise(resolve => {
axios.post(url, json).then(res=> {
/*do something*/
resolve(res)
})
}
}
核心方法:
let getData = function (key, expiresMinutes, requestMethod, ...param) {
let expires = key + "Expires";
let p = localStorage.getItem(key);
let pe = localStorage.getItem(expires);
let parse = JSON.parse(p);
let now = new Date().getTime();
console.log("key = " + key)
console.log(parse)
//当localStorage中有数据,且在有效期内时,直接返回当中的数据
if (p !== null && now - pe < 1000 * 60 * expiresMinutes) {
return new Promise(resolve => {
resolve(parse);
});
}
//当localStorage中无数据,或数据过期时,执行请求方法获取数据,并将获取到的数据存储到localStorage中
return new Promise(resolve => {
requestMethod(...param).then(res => {
if (res === null) {
alert("数据请求失败");
}
localStorage.setItem(key, JSON.stringify(res));
localStorage.setItem(expires, JSON.stringify(now));
resolve(res);
});
})
}
调用
getData(key, expiresMinutes, requestMethod, ...param).then(res=>{
/*do something*/
})