网站首页 > 技术文章 正文
在处理前端重复请求问题时,通过共享 Promise 实现请求合并和结果复用是常见的高效解决方案。以下为详细实现思路和代码示例:
一、问题场景分析
当出现以下情况时,可能导致重复请求:
- 用户频繁点击触发按钮事件
- 组件快速重复挂载/更新
- 输入框实时搜索请求(如防抖失效)
- 多个独立组件同时加载相同数据
二、核心实现思路
- 创建请求缓存池:存储正在进行的请求
- 请求唯一标识:通过参数生成请求唯一键
- Promise 复用:相同请求返回缓存中的 Promise
- 缓存清理机制:请求完成后自动清理缓存
三、完整实现方案
1. 基础版实现(ES6+)
// 请求缓存池
const requestCache = new Map();
function generateRequestKey(config) {
return `${config.method}-${config.url}-${JSON.stringify(config.params)}`;
}
async function sharedRequest(config) {
const requestKey = generateRequestKey(config);
// 存在进行中的相同请求
if (requestCache.has(requestKey)) {
return requestCache.get(requestKey);
}
// 创建新请求并缓存
const requestPromise = axios(config)
.then(response => {
requestCache.delete(requestKey); // 成功清除缓存
return response;
})
.catch(error => {
requestCache.delete(requestKey); // 失败也清除缓存
throw error;
});
requestCache.set(requestKey, requestPromise);
return requestPromise;
}
2. 高级功能增强版
class RequestPool {
constructor() {
this.pool = new Map();
this.defaultTTL = 5000; // 默认缓存5秒
}
getKey(config) {
const { method, url, params, data } = config;
return `${method}-${url}-${JSON.stringify(params)}-${JSON.stringify(data)}`;
}
async request(config) {
const key = this.getKey(config);
const now = Date.now();
// 存在未过期的缓存
if (this.pool.has(key)) {
const { expire, promise } = this.pool.get(key);
if (expire > now) return promise;
}
// 创建新请求
const promise = axios(config).finally(() => {
// 自动清理或保留缓存
if (!config.keepAlive) {
this.pool.delete(key);
}
});
// 缓存带有效期
this.pool.set(key, {
promise,
expire: Date.now() + (config.cacheTTL || this.defaultTTL)
});
return promise;
}
// 手动清除缓存
clearCache(key) {
this.pool.delete(key);
}
}
// 使用示例
const apiPool = new RequestPool();
function fetchUserData(userId) {
return apiPool.request({
method: 'GET',
url: '/api/user',
params: { id: userId },
cacheTTL: 10000 // 自定义缓存时间
});
}
四、关键点解析
1. 请求唯一标识设计
- 组合关键参数:method + url + 序列化后的params/data
- 序列化优化:
function stableStringify(obj) {
const keys = Object.keys(obj).sort();
return JSON.stringify(keys.map(k => ({ [k]: obj[k] })));
}
2. 缓存清理策略
策略类型 | 实现方式 | 适用场景 |
即时清理 | 请求完成后立即删除 | 常规数据请求 |
TTL 过期 | 检查expire字段 | 需要短期缓存的数据 |
手动清理 | 提供clearCache方法 | 明确知道数据变更时 |
LRU 算法 | 维护使用记录+最大数量限制 | 高频请求且内存敏感场景 |
3. 错误处理要点
.catch(error => {
// 特殊错误处理:网络错误可保留短暂缓存
if (error.isNetworkError) {
setTimeout(() => this.pool.delete(key), 1000);
}
throw error;
});
五、适用场景对比
方案 | 优点 | 缺点 | 最佳使用场景 |
基础版 | 实现简单、内存占用少 | 缺乏高级控制 | 简单页面、少量API |
类封装版 | 功能完善、扩展性强 | 实现复杂度较高 | 中大型项目、复杂场景 |
第三方库(swr) | 开箱即用、功能丰富 | 需要学习新API | 需要快速实现的复杂缓存需求 |
六、延伸优化方向
- 请求竞速处理:
let abortController;
function smartRequest() {
if (abortController) {
abortController.abort();
}
abortController = new AbortController();
return fetch(url, { signal: abortController.signal });
}
- 本地缓存融合:
const response = await request();
if (response.ok) {
localStorage.setItem(cacheKey, {
data: response.data,
expire: Date.now() + 3600000
});
}
- 可视化监控:
// 在RequestPool类中添加
getCacheStatus() {
return Array.from(this.pool.entries()).map(([key, item]) => ({
key,
expireIn: item.expire - Date.now(),
status: item.promise.isPending ? 'pending' : 'settled'
}));
}
通过这种实现方式,可以有效解决以下问题:
- 减少 50%-90% 的重复网络请求
- 避免组件重复渲染造成的性能损耗
- 保证多个组件间的数据一致性
- 降低服务端并发压力
实际项目中可根据具体需求选择基础版或增强版实现,建议配合 TypeScript 进行类型约束以保证代码健壮性。
- 上一篇: 云智慧透视宝前端架构那些事儿_云透传平台
- 下一篇: 面试必杀题:当发生OOM时,进程还能处理请求吗
猜你喜欢
- 2025-10-02 面试必杀题:当发生OOM时,进程还能处理请求吗
- 2025-01-02 前后端数据交互(六)——ajax 、fetch 和 axios 优缺点及比较
- 2025-01-02 前端报504错误如何定位
- 2025-01-02 测试提了个bug,为什么你多了个options请求?
- 2025-01-02 如果用户觉得 web 应用反应卡顿, 主要从哪几个方面来排查?
- 2025-01-02 Vue短文:如何在HTTP请求时传递自定义头部
- 2025-01-02 前端小伙伴,axios 是如何封装 HTTP 请求的?(看完会了吗)
- 2025-01-02 SpringMVC实现原理之DispatcherServlet处理请求的过程
- 2025-01-02 Background Sync出世!前端离线请求火起来?
- 2025-01-02 最简单的 6 种防止数据重复提交的方法!(干货)
你 发表评论:
欢迎- 最近发表
-
- Three.js vs Unity:工业可视化为何选择Web方案?
- 一款全新Redis UI可视化管理工具,支持WebUI和桌面——P3X Redis UI
- 时间线可视化实战:三款AI工具实测,手把手教你制作人生轨迹图
- 【推荐】一款可视化在线 Web 定时任务管理平台,支持秒级任务设置
- 重磅更新!FastDatasets 推出可视化 Web 界面
- 模具设计之UG钣金实例教程(3)_ug钣金基础教程
- 前端基于 RBAC 模型的权限管理实现
- 别再把JWT存在localStorage里了!2025年前端鉴权新思路
- 模具设计之曲面造型中不圆润的曲面如何处理技巧
- 9个专业级别的CSS技巧区分了解和精通的鸿沟
- 标签列表
-
- 前端设计模式 (75)
- 前端性能优化 (51)
- 前端模板 (66)
- 前端跨域 (52)
- 前端缓存 (63)
- 前端aes加密 (58)
- 前端脚手架 (56)
- 前端md5加密 (54)
- 前端路由 (61)
- 前端数组 (73)
- 前端js面试题 (50)
- 前端定时器 (59)
- Oracle RAC (76)
- oracle恢复 (77)
- oracle 删除表 (52)
- oracle 用户名 (80)
- oracle 工具 (55)
- oracle 内存 (55)
- oracle 导出表 (62)
- oracle约束 (54)
- oracle 中文 (51)
- oracle链接 (54)
- oracle的函数 (58)
- oracle面试 (55)
- 前端调试 (52)
本文暂时没有评论,来添加一个吧(●'◡'●)