异步缓存2-cacheCall

244 阅读1分钟

在前端开发中,有时带有缓存功能的fetch请求可以提高性能,以前曾写过一篇帖子异步缓存-cacheCall,那个里面是通过回调获取返回值,现在promise大行其道,这次封装的函数通过promise.resole获取返回值,普通的fetch请求如下:

const get = ({ url }) => {
  return fetch(url).then(res=>res.json())
}

我们通过cacheCall函数可以对上述函数进行包裹处理,使其具有cache功能

//fn:不带cache功能返回promise的函数,interval:缓存有效期,单位ms
const cacheCall = (fn, interval) => {
    const caches = {}
    setInterval(() => {
      Object.keys(caches).forEach(key => {
        const cache = caches[key] 
        if (cache && !cache.pending && new Date() - cache.time > interval) delete caches[key]
      })
    }, 60 * 1000)
    return (arg) => {
      const key = JSON.stringify(arg)
      return new Promise((resole, reject) => {
        const resoleTask=(res)=>{
          const cache = caches[key]
          cache.resoleTask.forEach(cb => cb(res))
          Object.assign(cache, { resoleTask: [],rejectTask:[], value:res, time: new Date(), pending: false })
        }
        const rejectTask=(res)=>{
          const cache = caches[key]
          cache.rejectTask.forEach(cb => cb(res))
          delete caches[key]
        }
        const cache = caches[key]
        if (cache) {
          cache.pending ? (cache.resoleTask.push(resole),cache.rejectTask.push(reject)) : resole(cache.value)
        } else {
          caches[key] ={ pending: true, resoleTask: [resole],rejectTask:[reject] } 
          fn(arg).then(resoleTask).catch(rejectTask)
        }
      })
    }
}

调用例子如下:

const url = './data.json'
const cacheGet = cacheCall(get, 1000 * 60)
cacheGet({ url }).then(res => {
  console.log(res)
})
cacheGet({ url }).then(res => {
  console.log(res)
})

测试结果如下:

image.png

image.png

可以看出两次调用输出了两次结果,但是只做了一次http请求,我们故意进行错误调用看会发生什么

const url = './data2.json'
const cacheGet = cacheCall(get, 1000 * 60)
cacheGet({ url }).then(res => {
  console.log(res)
}).catch(res=>{
  console.log('err1',res)
})
cacheGet({ url }).then(res => {
  console.log(res)
}).catch(res=>{
  console.log('err2',res)
})

image.png

image.png

可以看出两次错误调用输出了两次结果,只做了一次http请求