背景
在实际开发中,前端页面可能会由于用户的快速点击、组件的多次渲染或其他触发机制,导致重复发送相同的请求。这不仅浪费网络资源,还可能导致数据重复加载或状态异常。为了解决这个问题,我们可以使用单例 Promise 模式。
单例 Promise 工具函数
下面是一个简单易用的单例 Promise 工具函数:
export function singletonPromise(fn) {
const promisesMap = new Map();
return (...args) => {
const key = JSON.stringify(args); // 根据参数生成唯一的键
if (!promisesMap.has(key)) {
const promise = fn(...args)
.then((result) => {
setTimeout(() => { // 1000ms以内的请求,视为重复请求,直接返回上次的结果
promisesMap.delete(key); // 清理完成的 Promise
}, 1000);
return result;
})
.catch((error) => {
promisesMap.delete(key); // 清理失败的 Promise
throw error;
});
promisesMap.set(key, promise);
}
return promisesMap.get(key);
};
}
关键特性
- 避免重复请求: 相同参数的请求只会触发一次,后续的调用直接复用已有的 Promise。
- 参数唯一键: 使用
JSON.stringify将参数序列化为唯一标识,适配不同参数的请求场景。 - 自动清理: 请求完成(无论成功或失败)后,自动释放对应的键,避免内存泄漏。
使用示例
以下是如何在实际场景中使用该工具函数:
// 创建一个需要单例化的异步函数
const fetchData = singletonPromise((url) =>
fetch(url).then((res) => res.json())
);
// 示例:发起请求
fetchData('https://api.example.com/data')
.then((data) => console.log('Data:', data))
.catch((error) => console.error('Error:', error));
// 即使多次调用相同的 URL,也只会发送一次实际请求
fetchData('https://api.example.com/data');
fetchData('https://api.example.com/data');
// 不同参数的请求会分别发送
fetchData('https://api.example.com/other-data')
.then((data) => console.log('Other Data:', data));
适用场景
- 防止重复点击: 按钮或操作多次触发同一个请求时。
- 组件渲染: 同一数据在多组件中重复请求的问题。
- 定时轮询: 保证轮询任务中相同参数的请求不会重复发送。
总结
通过单例 Promise 工具函数,可以有效减少重复请求的发生,提高页面的性能和用户体验。简单的实现方式适用于大多数场景,是前端开发中不可或缺的小工具之一。