让前端飞Web前端之路

promise实现前端缓存

2019-12-12  本文已影响0人  nick121212

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);
上一篇下一篇

猜你喜欢

热点阅读