最近的工作中需要实现将部分接口的数据缓存在页面以减少请求、加快页面响应的需求,现总结一下实现这个需求的过程
具体需求
缓存数据的场景分为两种:
- 与用户无关的数据
- 与用户相关的数据
需要使用缓存的接口是无参数且为get类型的请求
应用内代码简介
这是一个使用vue-cli创建的vue2.0项目,使用axios库来发送接口请求
大致思路
- 对于用户无关的数据,可以存储在
localStorage中 - 对于用户相关的数据,可以存储在
sessionStorage中 - 不修改原有的接口使用方法,创建一个新的接口调用函数,并使调用方式保持不变
// 发送请求并将数据缓存到localStorage的方法
// 参数axiosConfig为普通axios方法所使用的参数
export function localRequest(axiosConfig) {
// service为axios.create方法创建的实例
return service(axiosConfig);
}
- 调用该方法时,先创建用于保存的
key,再在对应的storage中查找是否有该key的缓存值,有则返回一个伪造的axios请求的Promise结果对象
export function localRequest(axiosConfig) {
// 先创建缓存数据在localStorage中的key,由于请求皆为无参数的get请求,所以仅用url作为key即可
// LOCALSTORAGE_CACHE_VERSION是一个存储版本号,后面有详细解释
const localKey = axiosConfig.url + LOCALSTORAGE_CACHE_VERSION;
// 尝试去获取localStorage中的缓存值,并封装为一个伪造的axios方法返回值
const storeResponse = getStoreResponse(localKey, window['localStorage']);
if(storeResponse) {
// 如果本地有存储的值,则上面的方法会返回一个Promise实例
return storeResponse;
}
// 本地没有缓存则调用接口去请求数据
return service(axiosConfig);
}
// 获取存储中的数据
function getStoreResponse(localKey, storage) {
const item = storage.getItem(localKey);
if(item) {
try {
const data = JSON.parse(item);
if(data) {
// 成功拿到
return Promise.resolve({
status: 200,
statusText: 'ok',
data,
})
}
} catch (err) {
// 这里不做任何处理
}
}
// 如果未取到缓存中的结果,则会返回undefined
}
- 没有缓存时请求到数据后需要将响应数据保存在本地存储中,并且需注意的是要对请求结果做判断,只保存成功拿到数据的结果,否则一次失败后将无法再获取成功的结果
export function localRequest(axiosConfig) {
// ...
// 省略部分代码
if(StoreResponse) {
return storeResponse;
}
// 在axios方法参数中配置请求成功后的处理
axiosConfig.transformResponse = [
data => {
const jsonData = JSON.parse(data);
// 判断请求结果是否ok
if(jsonData.code === 'sucess') {
// 只保存成功响应的结果
window['localStorage'].setItem(locakKey, data);
}
return jsonData;
}
];
return service(axiosConfig);
}
至此,该localRequest便可以用于替换axios.create创建的实例,来请求可以缓存于本地的用户无关数据
- 创建用于缓存数据到localStorage的key时,使用了
LOCALSTORAGE_CACHE_VERSION常量,该常用是使用webpack.DefinePlugin插件注入的值,这样是为了让每次重新发版后可以自动刷新本地缓存的数据
// vue.config.js中
{
configureWebpack: {
// webpack配置
plugins: [
new webpack.DefinePlugin({
// 这里使用Date.now()即可,为了美观也可以使用uuid或nanoid库
// 必须要使用JSON.stringify()方法给普通值加一对引号,否则会报错
LOCALSTORAGE_CACHE_VERSION: JSON.stringify(Date.now())
})
]
}
}
- 创建sessionRequest方法来请求用户相关的数据,与localRequest的区别在于key的创建
// 创建local缓存的key由参数路径和本地存储版本号组成
const localKey = axiosConfig.url + LOCALSTORAGE_CACHE_VERSION;
// 创建session缓存的key需由用户id+参数路径组成
const sessionKey = store.state.userInfo.userId + axiosConfig.url;
// 一般而言无需考虑session缓存的版本号,因为其随着页面关闭就会消失
-
关于session缓存用户相关的数据,如果没有
userId可供使用,可以使用一个全局的key来代替,确保该key会随着页面的刷新而变化即可,比如可以用进入页面后的某个时间点的时间戳 -
清除旧的localStorage缓存,由于浏览器对localStorage的大小是有限制的,所以在发版后对于先前保存的数据应当予以清除
export function clearLocalStorageCache() {
// 这个key是存储本地缓存版本号的
const key = 'LOCALSTORAGE_CACHE_VERSION';
// 获取当前的本地存储版本号
const localVersionKey = LOCALSTORAGE_CACHE_VERSION;
// 获取旧的本地存储版本号
const storageLocalVersionKey = window['localStorage'].getItem(key);
// 如果新旧版本号不一致,则需要清除旧的缓存数据,并重新设置版本号
if(Number(storageLocalVersionKey) !== localVersionKey) {
for( let key of Object.keys(window['localStorage']) ) {
if(key.endsWith(storageLocalVersionKey)) {
window['localStorage'].removeItem(key);
}
}
window['localStorage'].setItem(key, localVersionKey);
}
}
这个方法可以在进入页面时就调用,我这边是在main.js中调用的