举个常见的场景: 在调用接口前都需要做一个权限 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);
来源: http://www.jianshu.com/p/15a113eca335