前端并发请求控制实践

46 篇文章 0 订阅
46 篇文章 0 订阅

单个请求

实现效果:

 

function timeout(time) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("success");
    }, time);
  });
}

// timeout(1000).then(res=>{
//     console.log(res)
// })

class SuperTask {
  constructor(paralleCount = 2) {
    this.paralleCount = paralleCount; // 并发数量
    this.taskList = []; // 任务列表
    this.runningCount = 0; // 正在执行的任务数量
  }

  add(task) {
    return new Promise((resolve, reject) => {
      this.taskList.push({
        task,
        resolve,
        reject,
      });
      this._run();
    });
  }
  _run() {
    // 依次执行任务队列里的任务
    while (this.runningCount < this.paralleCount && this.taskList.length) {
      // 获取任务
      const { task, resolve, reject } = this.taskList.shift();
      this.runningCount++;
      // 执行任务
      task()
        .then(resolve, reject)
        .finally(() => {
          this.runningCount--;
          this._run();
        });
    }
  }
}

const superTask = new SuperTask();

function addTask(time, name) {
  superTask
    .add(() => timeout(time))
    .then((res) => {
      console.log(name);
    });
}

addTask(1000, "1");
addTask(1000, "2");
addTask(1000, "3");
addTask(1000, "4");
addTask(1000, "5");
addTask(1000, "6");
addTask(1000, "1");
addTask(1000, "2");
addTask(1000, "3");
addTask(1000, "4");
addTask(1000, "5");
addTask(1000, "6");

  1. timeout(time) 函数:

    • 这个函数返回一个 Promise,在指定的时间(毫秒)后会 resolve 为字符串 "success"。
  2. SuperTask 类:

    • SuperTask 类负责管理一个任务列表,并以并行的方式执行这些任务,同时限制最大并发数量。
    • 构造函数接受一个可选的 paralleCount 参数,用于设置最大并发任务数。
    • add(task) 方法将新的任务添加到任务列表中,并启动任务执行过程。
    • _run() 方法负责从任务列表中取出任务,并在允许的并发数范围内执行这些任务。
  3. addTask(time, name) 函数:

    • 这个函数创建一个新的任务,通过调用 superTask.add(() => timeout(time)) 将任务添加到 SuperTask 实例中。
    • 当任务执行完成后,会打印出任务名称。

数据数组发送请求

const max = 6; // 最大请求数
const taskPool = []; // 请求队列
const formDataArray = [...formDatas]; // 创建一个副本,以免修改原始数组,原formDatas数据数组

async function uploadFiles() {
  const results = [];

  while (formDataArray.length > 0) {
    // 向请求池添加新的请求,直到达到最大值
    while (taskPool.length < max && formDataArray.length > 0) {
      const formData = formDataArray.shift();
      const promise = fetch("http://localhost:3000/upload", {
        method: "POST",
        body: formData,
      });
      taskPool.push(promise);
    }

    // 等待最先完成的请求
    const [firstFinishedPromise] = await Promise.race(taskPool);
    results.push(await firstFinishedPromise);
    taskPool.splice(taskPool.indexOf(firstFinishedPromise), 1);
  }

  // 等待所有请求完成
  await Promise.all(taskPool);

  return results;
}

uploadFiles()
  .then((results) => {
    console.log(results);
  })
  .catch((error) => {
    console.error(error);
  });

  1. 定义常量 max,表示最大并发请求数。

  2. 创建 taskPool 数组用于存储当前正在执行的请求,以及 formDataArray 数组用于存储待上传的文件数据。

  3. 定义 uploadFiles() 异步函数:

    • 初始化 results 数组用于存储上传结果。

    • 在 formDataArray 还有未上传的文件时,进行以下操作:

      • 将新的请求添加到 taskPool 中,直到达到最大并发数 max
      • 使用 Promise.race() 等待最先完成的请求,并将其从 taskPool 中移除,同时将结果推入 results 数组。
    • 最后使用 Promise.all() 等待 taskPool 中所有请求完成。

    • 返回 results 数组。

  4. 调用 uploadFiles() 函数,并在成功和失败的情况下分别打印结果和错误信息。

这个实现的主要思路是:

  1. 限制并发请求数量,避免过多的请求同时发送导致资源耗尽。
  2. 使用 Promise.race() 等待最先完成的请求,并处理其结果。
  3. 使用 Promise.all() 确保所有请求都完成后再返回结果。

原文链接:https://juejin.cn/post/7406697002539483176

  • 16
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值