利用promise实现一个请求队列控制最大请求数

在前端开发中,经常需要控制并发请求的数量以避免服务器过载或浏览器性能问题。下面我使用 Promise 实现一个请求队列控制器。

基本思路:

  1. 维护一个等待队列和一个执行队列
  2. 当有新的请求加入时,先放入等待队列
  3. 当执行队列有空位时,从等待队列取出请求执行
  4. 请求完成后,从执行队列移除,并检查是否有等待的请求
js 复制代码
class PromiseQueue {

  constructor(limit = 2) {
    this.limit = limit;
    this.running =0;
    this.queue=[];
}


    add(fn)
  {
    return new Promise((resolve, reject) => {

      const executeFn = async () => {
        this.running++;
        try {
          const result = await fn();
          resolve(result);
        } catch (error) {
          reject(error);
        } finally {
          this.running--;
          this.next();
        }
      };

      this.queue.push(executeFn);
      this.next();
    });
  }

  next() {
    if ( this.queue.length && this.running < this.limit ) {
      const fn = this.queue.shift();
      fn();
    }
  }
} 

测试用例

js 复制代码
// 测试代码
async function testPromiseQueue() {
  // 1. 创建一个最大并发数为2的队列
  const queue = new PromiseQueue(2);
  const results = [];
  const startTime = Date.now();

  // 辅助函数:创建一个带延迟的测试任务
  const createTask = (id, delay, shouldFail = false) => async () => {
    const start = Date.now() - startTime;
    console.log(`任务 ${id} 开始执行 (延迟 ${delay}ms) [时间: ${start}ms]`);
    await new Promise(resolve => setTimeout(resolve, delay));
    if (shouldFail) {
      throw new Error(`任务 ${id} 模拟失败`);
    }
    console.log(`任务 ${id} 完成 (耗时 ${delay}ms) [时间: ${Date.now() - startTime}ms]`);
    return id;
  };

  // 2. 添加测试任务
  // 快速任务 (100ms)
  queue.add(createTask(1, 100))
    .then(res => results.push(`任务1成功: ${res}`))
    .catch(err => results.push(`任务1失败: ${err.message}`));

  // 慢速任务 (200ms)
  queue.add(createTask(2, 200))
    .then(res => results.push(`任务2成功: ${res}`))
    .catch(err => results.push(`任务2失败: ${err.message}`));

  // 快速失败任务 (100ms)
  queue.add(createTask(3, 100, true))
    .then(res => results.push(`任务3成功: ${res}`))
    .catch(err => results.push(`任务3失败: ${err.message}`));

  // 超慢速任务 (300ms)
  queue.add(createTask(4, 300))
    .then(res => results.push(`任务4成功: ${res}`))
    .catch(err => results.push(`任务4失败: ${err.message}`));

  // 快速任务 (100ms)
  queue.add(createTask(5, 100))
    .then(res => results.push(`任务5成功: ${res}`))
    .catch(err => results.push(`任务5失败: ${err.message}`));

  // 3. 等待所有任务完成
  await new Promise(resolve => setTimeout(resolve, 1000));

  // 4. 打印测试结果
  console.log('\n最终结果:');
  console.log(results.sort().join('\n'));

  // 5. 验证并发数是否正确
  console.log('\n验证:');
  console.log(`最大并发数: ${queue.limit}`);
  console.log(`运行中任务数: ${queue.running}`);
  console.log(`队列中剩余任务: ${queue.queue.length}`);
}

// 执行测试
testPromiseQueue();
相关推荐
To_OC15 分钟前
LC 42 接雨水:暴力超时卡半天?前后缀数组一用就通了
javascript·算法·leetcode
小林ixn26 分钟前
从 ??= 到 onKeyDown:一个 React 组件的“自我修养”
前端·javascript·react.js
এ慕ོ冬℘゜1 小时前
前端实战:jQuery 多条件联合搜索(标题模糊查询 + 日历时间段筛选)
前端·javascript·jquery
随心点儿2 小时前
js postMessage 实现跨域发送消息-应用示例
javascript·ecmascript·postmessage
kyriewen3 小时前
我让AI改一个bug——它偷偷动了5个我没让它碰的地方
前端·javascript·ai编程
gis开发之家8 小时前
《Vue3 从入门到大神35篇》Vue3 源码详解(五):effect 依赖收集原理——track 与 trigger 是如何工作的?
javascript·typescript·前端框架·vue3·vue3源码
橘子星9 小时前
我一个前端切图仔,凭什么能在浏览器里跑大模型?
前端·javascript·前端框架
半个落月9 小时前
用 LangChain JS 做可控写作实验:理解温度参数、提示词与异步调用
javascript·人工智能·后端
观远数据9 小时前
Excel到数据资产池:文件数据入湖的治理规范怎么建
前端·javascript·excel
CoderWeen9 小时前
我写了个能一步步点着看的 Dijkstra 可视化项目(Vue3 + Leaflet + Generator)
前端·javascript·vue.js