在 ZSFT 实现热度值时,遇到了列出字体列表时需要同时调用热度值 fetch 函数导致重复的多次请求,即便 fetch 的函数已经设置了如果本地有数据则返回本地数据,但同时调用的时间点本地确实没有数据,也就导致了这一问题。(这样的问题或许很常见?)在网络上也无法找到相关的建议 ... 当然或许是我的搜索关键词有问题 ...
ZSFT 的方法是返回全站的热度值数据并在过期前使用本地缓存数据,因为那的确并不大,并且可以大幅度降低服务器压力,但如果为每个数据碎片化的单个请求,则不适用此方法。
以下请直接查看源代码,包括过期处理:
// 正在请求标识
let getThisFetching = false;
// 返回的 Promise
let getFetchPromise = null;
async function get() {
let obj = null;
const localData = localStorage.getItem("localData");
const now = new Date();
const localDataTime = localStorage.getItem("localDataTime") ? new Date(localStorage.getItem("localDataTime")) : null;
// 指定 1 天后过期,重新获取
const oneDay = (new Date(now.getTime() + (1 * 24 * 60 * 60 * 1000))).toISOString();
// 如果没有本地数据或者本地数据过期则执行,否则直接返回本地数据
if (!localData || (localDataTime && localDataTime < now)) {
// 如果正在请求为 true 则不再请求而直接等待返回
if (!getThisFetching) {
getThisFetching = true;
getFetchPromise = fetch("XXX", {
method: "GET",
}).then(i => i.json()).then(data => {
localStorage.removeItem("localDataTime");
localStorage.setItem("localDataTime", oneDay);
localStorage.setItem("localData", JSON.stringify(data));
getThisFetching = false;
getFetchPromise = null;
return data;
}).catch(error => {
getThisFetching = false;
getFetchPromise = null;
throw error;
});
};
obj = await getFetchPromise;
} else {
obj = JSON.parse(localData);
};
return obj;
};
实际上,这段代码和正常的可返回本地数据的 fetch 请求一样,只不过增加了两个变量,
首先,判断 !getThisFetching 也就是是否正在被请求,如果是,则不执行请求,包括请求前,会将 getThisFetching 设置为 true ,代表正在请求, fetch 被赋值给 getFetchPromise ,这样就可以让 obj 等待它
fetch 被赋值在函数外部,每次调用则不会被重置状态,第一个请求会触发 fetch ,因为 !getThisFetching 成立,执行 fetch 然后等待 obj ,但到了第二个请求则不成立,就会直接等待 obj 也就是最终输出。