You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何按来源将请求生成的Promise按10秒时间间隔批量处理?

按来源实现10秒窗口的Promise批量处理

这个需求本质是按请求来源做时间窗口内的请求聚合批量处理,我给你写一个简洁且健壮的实现方案,附带详细解释:

核心思路

我们需要给每个请求来源维护一个「等待批次」:

  1. 用Map存储各来源的批次信息(定时器ID、待处理请求队列)
  2. 收到请求时,先检查对应来源是否已有等待中的批次:
    • 有则直接把请求加入队列
    • 没有则创建新队列+启动10秒定时器,定时器到期后批量处理整个队列的请求
  3. 每个入队的请求会返回一个Promise,最终会在批次处理时拿到自己的执行结果

代码实现(JavaScript)

// 全局缓存:key=来源标识,value={定时器ID, 请求队列}
const sourceBatchCache = new Map();

/**
 * 将请求加入对应来源的10秒批次队列
 * @param {string} source - 请求的唯一来源标识(比如来源ID、域名等)
 * @param {Function} apiCallFn - 返回Promise的内部API调用函数(比如 () => fetch('/internal-api'))
 * @returns {Promise} 返回当前请求的最终执行结果
 */
function batchRequestBySource(source, apiCallFn) {
  return new Promise((resolve, reject) => {
    // 检查当前来源是否已有正在等待的批次
    if (sourceBatchCache.has(source)) {
      const batch = sourceBatchCache.get(source);
      // 将当前请求的回调和执行函数加入队列
      batch.queue.push({
        execute: apiCallFn,
        resolve,
        reject
      });
    } else {
      // 初始化新批次的队列
      const requestQueue = [{
        execute: apiCallFn,
        resolve,
        reject
      }];

      // 启动10秒定时器,到期后处理整个批次
      const timerId = setTimeout(() => {
        // 先从缓存移除批次,避免后续请求重复触发
        sourceBatchCache.delete(source);

        // 批量执行所有请求,用allSettled确保每个请求的结果都能被处理
        Promise.allSettled(requestQueue.map(item => item.execute()))
          .then(results => {
            // 把每个请求的结果对应到各自的Promise回调
            results.forEach((result, index) => {
              const target = requestQueue[index];
              if (result.status === 'fulfilled') {
                target.resolve(result.value);
              } else {
                target.reject(result.reason);
              }
            });
          });
      }, 10000); // 10秒窗口时长

      // 将新批次存入缓存
      sourceBatchCache.set(source, {
        timerId,
        queue: requestQueue
      });
    }
  });
}

关键细节说明

  • 按来源隔离:用Map确保不同来源的请求完全独立,不会互相干扰批次窗口
  • 请求结果精准传递:每个入队请求的resolve/reject会被单独存储,批量处理后一一对应返回,调用方感知不到批量逻辑,和直接调用API体验一致
  • 健壮性保障:使用Promise.allSettled而不是Promise.all,避免单个请求失败导致整个批次的所有请求都被标记为失败
  • 内存泄漏预防:定时器触发后立即从缓存删除对应批次,同时可以补充一个清理函数来处理服务关停时的残留定时器:
// 清理所有未处理的批次定时器(比如服务 shutdown 时调用)
function clearAllPendingBatches() {
  for (const { timerId } of sourceBatchCache.values()) {
    clearTimeout(timerId);
  }
  sourceBatchCache.clear();
}

使用示例

// 模拟来自不同来源的请求
batchRequestBySource('source-A', () => fetch('/internal-api?data=A1'))
  .then(res => console.log('A1结果:', res))
  .catch(err => console.error('A1失败:', err));

// 10秒内来自source-A的第二个请求,会被加入同一个批次
setTimeout(() => {
  batchRequestBySource('source-A', () => fetch('/internal-api?data=A2'))
    .then(res => console.log('A2结果:', res))
    .catch(err => console.error('A2失败:', err));
}, 5000);

// 来自source-B的请求,会开启独立的批次
batchRequestBySource('source-B', () => fetch('/internal-api?data=B1'))
  .then(res => console.log('B1结果:', res))
  .catch(err => console.error('B1失败:', err));

内容的提问来源于stack exchange,提问作者Learner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:52:42