FE-Interview icon indicating copy to clipboard operation
FE-Interview copied to clipboard

请实现一个 cacheRequest 方法,保证发出多次同一个 ajax 请求时都能拿到数据,而实际上只发出一次请求

Open lgwebdream opened this issue 5 years ago • 4 comments

lgwebdream avatar Jul 06 '20 16:07 lgwebdream

扫描下方二维码,获取答案以及详细解析,同时可解锁800+道前端面试题。

lgwebdream avatar Jul 06 '20 16:07 lgwebdream

const cacheRequest = (() => { const cacheMap: Map<string, CacheInfo> = new Map()

return <T>(p: () => Promise<T>, options: Params<T>) => { const cache = cacheMap.get(options.url) if (cache?.data) { if (cache.expireTime && Date.now() > cache.expireTime) { cacheMap.delete(options.url) } else { options.onSuccess(cache.data) return } }

const isCache = cacheMap.has(options.url)
if (!isCache) {
  if (cacheMap.size >= 10) {
    const firstKey = cacheMap.keys().next().value
    cacheMap.delete(firstKey)
  }
  cacheMap.set(options.url, {
    data: null,
    onSucCallbacks: [],
    expireTime: options.expireTime ? Date.now() + options.expireTime : 60 * 1000,
  })
  p().then(data => {
    const cache = cacheMap.get(options.url)
    cache.data = data
    cache.onSucCallbacks.forEach(cb => {
      cb(data)
    })
  })
}
cacheMap.get(options.url)?.onSucCallbacks.push(options.onSuccess)

} })()

interface CacheInfo<T> { data: T | null onSucCallbacks: ((data: T) => void)[] expireTime: number }

interface Params<T> { url: string onSuccess: (data: T) => void expireTime?: number }

kangdy avatar Sep 22 '23 09:09 kangdy

cacheRequest 实现

const cacheRequest = () => {
  const cache = new Map();

  /**
   * 生成正确的 cache key
   *
   * @author Harper.Gao
   * @param {*} url
   * @param {*} options
   * @return {*}
   */
  const generateCacheKey = (url, options) => {
    return `${url}${JSON.stringify(options)}`;
  };

  return async (url, options = {}) => {
    return new Promise(resolve => {
      const currentRequestKey = generateCacheKey(url, options);
      console.log(`Start handle url: ${url}, currentRequestKey: ${currentRequestKey}`);

      if (cache.has(currentRequestKey)) {
        console.log(`Current request hit cache! return result`);
        return resolve(cache.get(currentRequestKey));
      }

      const promise = fetch(url, options);
      cache.set(currentRequestKey, promise);

      promise.then(result => {
        cache.set(currentRequestKey, result);
        resolve(result);
      });
    });
  };
};

调用


const CacheRequest = () => {
  const request = cacheRequest();

  const onClickHandler = async () => {
    const result = await request("http://localhost:9090/api/getimmortal");
    console.log("result", result);
  };

  return (
    <div>
      <button onClick={onClickHandler}>Do cache request handler</button>
    </div>
  );
};
image

gaohan1994 avatar Apr 30 '24 05:04 gaohan1994