promise实现前端缓存
举个常见的场景:在调用接口前都需要做一个权限check,伪代码如下。
function getDataFromServer(url, options){
return checkFromServer().then(()=>{
return axios(url,options);
});
}
function checkFromServer(){
return axios("/check").then((res)=>{
if(res.data.code===403){
throw new Error("permission deny!");
}
});
}
// 调用接口数据
getDataFromServer("/data",{});
上面的代码看起来没有什么问题。如果考虑并发状态下呢?
getDataFromServer("/data",{});
getDataFromServer("/data1",{});
getDataFromServer("/data3",{});
在这里会触发三次的/check请求,从实际情况出发的话,在短期内可能只需要一次/check就可以了,性能上也能保障最优。
改造一下上面的代码:
const checkPromise = null;
function getDataFromServer(url, options){
return checkFromServer().then(()=>{
return axios(url,options);
});
}
function checkFromServer(){
// 如果有缓存,则直接使用缓存
if(checkPromise){
return checkPromise;
}
checkPromise = axios("/check").then((res)=>{
if(res.data.code===403){
throw new Error("permission deny!");
}
// 5秒后清除缓存
setTimeout(()=>{
checkPromise = null;
},5000);
}).catch((err)=>{
checkPromise = null;
throw err;
});
return checkPromise;
}
// 调用接口数据
getDataFromServer("/data",{});
getDataFromServer("/data1",{});
getDataFromServer("/data3",{});
如上代码,既解决了/check被调用多次的问题,也解决了并发时候的问题。看起来好像没什么问题了。
再来考虑一个场景把,假设/check数据需要缓存5分钟,5分钟之内都不会再去请求接口并考虑刷新页面的情况呢。
那就比较复杂了,数据可能需要落地到localstorage,可能还需要考虑缓存淘汰机制等情况。
这里有现成写好的库cache-in-stroage。
快速应用:
import { cacheDec } from "cache-in-storage";
const getTimeSpan = async (isError = false) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (isError) {
return reject(new Error("test"));
}
resolve(Date.now());
}, 200);
});
};
// 对getTimeSpan进行缓存,并把缓存结果放入localStorage
const getTimeSpanWithCache = cacheDec(getTimeSpan, "keyInCache", { cache:true }, localStorage);
// 此时执行方法返回的值都是相同的
getTimeSpanWithCache().then(console.log);
getTimeSpanWithCache().then(console.log);
getTimeSpanWithCache(true).catch(console.error);
网友评论