封装一个请求使其在多次调用时只发起一次请求,并返回相同结果,通常是通过请求去重(debouncing)来实现的。这种功能对于避免重复的网络请求、提高性能和减少不必要的负载非常有用。
同时,我们需要确保在请求完成之前,对相同请求的重复调用都会共享相同的请求 Promise。避免出现连续发出相同的请求,在第一个请求尚未完成时,那么可能会发出多个请求的情况。
可以通过以下步骤来实现这个功能:
1. 使用一个缓存机制
我们可以使用 JavaScript 对象或 Map 来缓存已经发起的请求,并在 subsequent 请求中返回缓存的结果。缓存的关键是确保相同的请求参数对应同一个缓存条目。
2. 创建请求缓存封装
以下是一个基于 axios
的请求去重的封装示例:
import axios from "axios";
// 请求缓存
const requestCache = new Map();
async function fetchData(url, params) {
// 生成缓存 key
const cacheKey = `${url}?${new URLSearchParams(params).toString()}`;
// 检查缓存中是否已有数据
if (requestCache.has(cacheKey)) {
return requestCache.get(cacheKey);
}
// 创建请求 Promise
const requestPromise = axios
.get(url, { params })
.then((response) => {
// 请求成功,存储结果
requestCache.delete(cacheKey); // 请求完成后,移除缓存
return response.data;
})
.catch((error) => {
// 请求失败,清除缓存
requestCache.delete(cacheKey);
throw error;
});
// 存储请求 Promise
requestCache.set(cacheKey, requestPromise);
// 返回 Promise
return requestPromise;
}
export default fetchData;
注意事项:
-
缓存请求 Promise:每个请求的 Promise 被缓存到 requestCache 中。后续的相同请求会返回这个缓存的 Promise。
-
请求完成后移除缓存:请求成功或失败后,删除缓存,以防止缓存中的 Promise 长时间存在,避免内存泄漏。
-
请求失败处理:如果请求失败,清理缓存并抛出错误,以便后续调用可以重新发起请求。
3. 使用请求缓存
使用封装好的 fetchData
函数来发起请求。多次调用相同的请求 URL 和参数只会发起一次网络请求,并返回相同的结果。
import fetchData from "./fetchData";
// 使用示例
fetchData("https://api.example.com/data", { id: 1 })
.then((data) => console.log(data))
.catch((error) => console.error(error));
// 再次调用相同的请求
fetchData("https://api.example.com/data", { id: 1 })
.then((data) => console.log(data)) // 共享相同的请求结果
.catch((error) => console.error(error));