MST
星途 面试题库

面试题:React函数式组件中模拟生命周期实现复杂数据缓存策略

在React函数式组件中,没有传统的生命周期概念。请阐述如何通过useEffect等Hook来模拟生命周期,实现一个复杂的数据缓存策略,该策略需满足:1. 支持多数据源缓存;2. 能够根据不同的缓存失效规则,自动更新或清理缓存;3. 处理缓存数据的并发访问问题。请给出详细的设计思路和完整代码实现。
30.9万 热度难度
前端开发React

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 多数据源缓存:使用一个对象来存储不同数据源的缓存数据,每个数据源可以通过唯一的标识符进行区分。
  2. 缓存失效规则:为每个数据源设置一个失效时间,在 useEffect 中通过比较当前时间和失效时间来决定是否更新或清理缓存。
  3. 并发访问处理:使用 Promiseasync/await 来确保对缓存数据的访问是顺序执行的,避免并发问题。同时可以使用一个锁机制来防止在缓存更新期间被其他请求访问。

代码实现

import React, { useEffect, useState } from 'react';

// 模拟获取数据的异步函数
const fetchData = (source) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(`Data from ${source}`);
    }, 1000);
  });
};

const CacheComponent = () => {
  const [cache, setCache] = useState({});
  const [lock, setLock] = useState(false);

  // 缓存更新或清理逻辑
  useEffect(() => {
    const checkCache = async () => {
      if (lock) return;
      setLock(true);
      const newCache = {...cache };
      Object.keys(newCache).forEach((source) => {
        const { data, expires } = newCache[source];
        if (Date.now() >= expires) {
          delete newCache[source];
        }
      });
      setCache(newCache);
      setLock(false);
    };
    checkCache();
  }, [cache, lock]);

  const getCachedData = async (source, expirationTime) => {
    if (lock) {
      // 如果锁存在,等待锁释放
      return new Promise((resolve) => {
        const interval = setInterval(() => {
          if (!lock) {
            clearInterval(interval);
            resolve(getCachedData(source, expirationTime));
          }
        }, 100);
      });
    }
    setLock(true);
    if (cache[source] && Date.now() < cache[source].expires) {
      setLock(false);
      return cache[source].data;
    }
    try {
      const data = await fetchData(source);
      const newCache = {...cache };
      newCache[source] = {
        data,
        expires: Date.now() + expirationTime
      };
      setCache(newCache);
      setLock(false);
      return data;
    } catch (error) {
      setLock(false);
      throw error;
    }
  };

  const handleClick = async () => {
    try {
      const data1 = await getCachedData('source1', 5000); // 5秒过期
      const data2 = await getCachedData('source2', 3000); // 3秒过期
      console.log(data1, data2);
    } catch (error) {
      console.error('Error fetching data:', error);
    }
  };

  return (
    <div>
      <button onClick={handleClick}>Fetch Data</button>
    </div>
  );
};

export default CacheComponent;

在上述代码中:

  1. cache 状态用于存储多数据源的缓存数据及其过期时间。
  2. lock 用于处理并发访问,在缓存更新或检查期间锁定,防止其他请求干扰。
  3. useEffect 用于定期检查缓存是否过期并进行清理。
  4. getCachedData 函数负责获取缓存数据,如果缓存过期则重新获取并更新缓存。
  5. handleClick 模拟对缓存数据的并发访问请求。