用Promise打造智能任务队列

你在电商大促时同时发起100个商品图片上传请求,服务器不堪重负直接崩溃------这就是并发控制的生死时刻!本文将用Promise打造一个智能任务队列,让异步任务像收费站车流一样高效运转。


为何需要任务队列?

当我们面对大量异步任务时:

javascript 复制代码
// 灾难现场:同时发起100个请求
for (let i = 0; i < 100; i++) {
  fetch(`/api/upload?img=product-${i}.jpg`)
}

痛点分析

  1. 服务器压力:瞬间100个并发请求可能压垮服务端
  2. 浏览器限制:Chrome最多允许6个同域名并发请求
  3. 资源竞争:过多任务同时执行导致内存/CPU暴涨

方案对比

方案 优势 劣势 适用场景
无控制直接并发 实现简单 易引发雪崩效应 少量安全请求
Promise.all 批量处理 无并发限制 小批量任务
Promise队列 精准流量控制 需额外实现 高并发场景

核心实现:智能限流控制器

1. 类结构设计 - 三个核心成员

javascript 复制代码
class TaskQueue {
  constructor(maxConcurrent) {
    this.maxConcurrent = maxConcurrent; // 最大并发数
    this.currentCount = 0;        // 当前进行中的任务数
    this.pendingQueue = [];       // 等待队列
  }

  // 添加任务到队列(核心方法)
  enqueue(taskFunc) {
    // 实现见下文
  }
}

2. 任务调度逻辑 - 收费站模型

javascript 复制代码
enqueue(taskFunc) {
  return new Promise((resolve, reject) => {
    // 封装原始任务(添加执行上下文)
    const wrappedTask = async () => {
      try {
        this.currentCount++;
        const result = await taskFunc(); // 执行实际任务
        resolve(result); // 传递结果
      } catch (error) {
        reject(error); // 传递错误
      } finally {
        this.currentCount--;
        this._runNext(); // 完成后触发下个任务
      }
    };

    // 决策逻辑:立即执行 or 加入等待
    if (this.currentCount < this.maxConcurrent) {
      wrappedTask();
    } else {
      this.pendingQueue.push(wrappedTask);
    }
  });
}

// 执行队列中的下一个任务
_runNext() {
  if (this.pendingQueue.length === 0) return;
  if (this.currentCount >= this.maxConcurrent) return;
  
  const nextTask = this.pendingQueue.shift();
  nextTask();
}

实战场景:电商图片上传系统

1. 模拟上传函数

javascript 复制代码
// 模拟带随机失败率的图片上传
const mockUpload = (id) => () => 
  new Promise((resolve, reject) => {
    const delay = 500 + Math.random() * 1000;
    setTimeout(() => {
      Math.random() > 0.2 
        ? resolve(`图片${id}上传成功`) 
        : reject(`图片${id}上传超时`);
    }, delay);
  });

2. 队列化上传 - 安全执行

javascript 复制代码
const uploadQueue = new TaskQueue(3); // 最大并发3

// 批量添加15个上传任务
const tasks = [];
for (let i = 1; i <= 15; i++) {
  tasks.push(uploadQueue.enqueue(mockUpload(i)));
}

// 全局结果处理
Promise.allSettled(tasks).then(results => {
  const success = results.filter(r => r.status === 'fulfilled');
  console.log(`成功率: ${success.length}/${results.length}`);
});

3. 执行效果

bash 复制代码
# 控制台输出示例
[执行中] 图片1 图片2 图片3
[完成] 图片1 (成功)
[开始] 图片4 (从队列补位)
[失败] 图片2 (超时)
[开始] 图片5 (继续补位)
...
最终统计:成功率: 12/15

关键优势

  • 流量平滑:始终维持≤3个并行上传
  • 错误隔离:单个失败不影响整体流程
  • 顺序保证:先进先出(FIFO)执行机制

性能优化:高级特性增强

1. 优先级队列 - VIP任务插队

javascript 复制代码
enqueue(taskFunc, priority = 0) {
  // ...(省略基础逻辑)
  const taskWrapper = { run: wrappedTask, priority };
  
  // 优先级插队逻辑
  if (this.currentCount >= this.maxConcurrent) {
    const index = this.pendingQueue.findIndex(
      t => priority > t.priority
    );
    index === -1 
      ? this.pendingQueue.push(taskWrapper)
      : this.pendingQueue.splice(index, 0, taskWrapper);
  }
}

// 使用示例 - 设置优先上传VIP商品图片
uploadQueue.enqueue(mockUpload('VIP'), 1); // 优先级高于默认0

2. 动态扩容 - 智能调整并发数

javascript 复制代码
// 根据网络状况自动调整
setConcurrent(newMax) {
  this.maxConcurrent = newMax;
  
  // 扩容时立即触发等待任务
  while (
    this.currentCount < this.maxConcurrent && 
    this.pendingQueue.length > 0
  ) {
    const task = this.pendingQueue.shift();
    task.run();
  }
}

方案对比:三种进阶实现方式

实现方案 实现复杂度 调度精度 功能扩展性 适用场景
基础Promise队列 ★★☆ ★★★ ★★☆ 简单并发控制
Priority Queue ★★★ ★★★ ★★★ 优先级任务系统
AsyncPool ★★☆ ★★☆ ★★☆ 固定池资源管理

选型黄金法则

  • 中小项目直接用基础Promise队列
  • 复杂系统选择Priority Queue方案
  • Node.js I/O密集型用AsyncPool

代码实现(完整版)

javascript 复制代码
class SmartTaskQueue {
  constructor(maxConcurrent = 5) {
    this.maxConcurrent = maxConcurrent;
    this.activeCount = 0;
    this.queue = [];
  }

  enqueue(task, priority = 0) {
    return new Promise((resolve, reject) => {
      const taskWrapper = async () => {
        this.activeCount++;
        try {
          const result = await task();
          resolve(result);
        } catch (error) {
          reject(error);
        } finally {
          this.activeCount--;
          this._dequeue();
        }
      };

      if (this.activeCount < this.maxConcurrent) {
        taskWrapper();
      } else {
        this.queue.push({ task: taskWrapper, priority });
        this.queue.sort((a, b) => b.priority - a.priority); // 优先级排序
      }
    });
  }

  _dequeue() {
    if (this.queue.length === 0) return;
    if (this.activeCount >= this.maxConcurrent) return;

    const nextTask = this.queue.shift().task;
    nextTask();
  }

  resize(newSize) {
    this.maxConcurrent = newSize;
    while (
      this.activeCount < this.maxConcurrent && 
      this.queue.length > 0
    ) {
      this._dequeue();
    }
  }
}

何时使用任务队列?

  1. 网络请求:API调用、文件上传/下载
  2. 资源加载:图片懒加载、分块加载大文件
  3. 硬件交互:蓝牙/串口设备指令发送
  4. 批量操作:数据库写入、日志上传

实战技巧:配合Web Worker使用可避免阻塞主线程

javascript 复制代码
// 在Worker中使用任务队列
const worker = new Worker('task-worker.js');
worker.postMessage({ type: 'INIT_QUEUE', maxConcurrent: 4 });
相关推荐
崔庆才丨静觅1 天前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60611 天前
完成前端时间处理的另一块版图
前端·github·web components
掘了1 天前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅1 天前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅1 天前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅1 天前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment1 天前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅1 天前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊1 天前
jwt介绍
前端
爱敲代码的小鱼1 天前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax