面试题答案
一键面试设计思路
- 多数据源缓存:使用一个对象来存储不同数据源的缓存数据,每个数据源可以通过唯一的标识符进行区分。
- 缓存失效规则:为每个数据源设置一个失效时间,在
useEffect
中通过比较当前时间和失效时间来决定是否更新或清理缓存。 - 并发访问处理:使用
Promise
和async/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;
在上述代码中:
cache
状态用于存储多数据源的缓存数据及其过期时间。lock
用于处理并发访问,在缓存更新或检查期间锁定,防止其他请求干扰。useEffect
用于定期检查缓存是否过期并进行清理。getCachedData
函数负责获取缓存数据,如果缓存过期则重新获取并更新缓存。handleClick
模拟对缓存数据的并发访问请求。