通过共享Promise解决前端重复请求的代码示例

 更新时间:2025年03月17日 09:53:17   作者:wordbaby  
在处理前端重复请求问题时,通过共享 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 进行类型约束以保证代码健壮性。

以上就是通过共享Promise解决前端重复请求的代码示例的详细内容,更多关于共享Promise解决重复请求的资料请关注脚本之家其它相关文章!

相关文章

  • 微信小程序音频录制波纹循环动画

    微信小程序音频录制波纹循环动画

    这篇文章主要为大家详细介绍了微信小程序音频录制波纹循环动画,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • 在html页面中包含共享页面的方法

    在html页面中包含共享页面的方法

    在静态html页面中引用子页面,类似动态页面方式inlcude一个共享的小片段
    2008-10-10
  • webpack配置sass模块的加载的方法

    webpack配置sass模块的加载的方法

    本篇文章主要介绍了webpack加载sass配置,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-07-07
  • JS实现手机号脱敏的方法详解

    JS实现手机号脱敏的方法详解

    脱敏指的是通过特定的技术手段对敏感数据进行处理,使其不再直接暴露给用户或系统,防止敏感信息泄露,通常在测试、开发、数据处理等场景中使用,本文给大家介绍了JS实现手机号脱敏的方法,需要的朋友可以参考下
    2025-03-03
  • js创建子窗口并且回传值示例代码

    js创建子窗口并且回传值示例代码

    本文为大家详细介绍喜爱使用js创建子窗口并且实现回传值的示例,感兴趣的朋友可以参考下哈,希望对大家有所帮助
    2013-07-07
  • js实现类似MSN提示的页面效果代码分享

    js实现类似MSN提示的页面效果代码分享

    这篇文章主要介绍了模仿MSN消息提示的效果,推荐给大家,有需要的小伙伴可以参考下。
    2015-08-08
  • JS生态系统加速模块解析赋能性能优化探索

    JS生态系统加速模块解析赋能性能优化探索

    这篇文章主要为大家介绍了JS生态系统加速模块解析赋能性能优化探索,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2024-01-01
  • js控制淡入淡出示例代码

    js控制淡入淡出示例代码

    淡入淡出效果想必大家都有见到过吧,在本文将为大家介绍下使用js如何控制淡入淡出,感兴趣的朋友可以参考下
    2013-11-11
  • 利用H5api实现时钟的绘制(javascript)

    利用H5api实现时钟的绘制(javascript)

    这篇文章主要为大家详细介绍了利用H5api实现时钟的绘制,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-09-09
  • JS使用iView的Dropdown实现一个右键菜单

    JS使用iView的Dropdown实现一个右键菜单

    这篇文章主要介绍了JS使用iView的Dropdown实现一个右键菜单功能,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-05-05

最新评论