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

使用async/await实现JS/TS异步有界队列的阻塞逻辑问题咨询

用Async/Await实现异步有界队列的阻塞逻辑

嘿,你这个需求完全可以用async/await结合Promise实现,根本不需要额外的协程!其实你要的“阻塞”本质上是异步等待——让enqueue/dequeue在条件不满足时暂停执行,直到队列状态符合要求,而这正是Promise+async/await擅长的场景。

核心思路

JavaScript里的async/await本身就是基于Promise的语法糖,而Promise是事件循环机制下的异步处理方案,不需要依赖协程就能实现这种“等待”逻辑——所谓的“阻塞”其实是让函数暂停在await处,释放事件循环去处理其他任务,等条件满足后再继续执行。

我们只需要给AsyncQueue类添加两个队列,用来保存等待中的Promise的resolve函数:

  • waitersEnqueue:当队列满时,enqueue的请求会在这里等待,直到有元素被dequeue后触发resolve
  • waitersDequeue:当队列空时,dequeue的请求会在这里等待,直到有元素被enqueue后触发resolve

修改后的完整代码

class AsyncQueue<T> {
  private queue: T[] = [];
  private maxSize: number = 1;
  // 保存等待入队的Promise解析函数
  private waitersEnqueue: (() => void)[] = [];
  // 保存等待出队的Promise解析函数
  private waitersDequeue: (() => void)[] = [];

  async enqueue(x: T) {
    // 循环检查队列是否已满,直到有可用空间
    while (this.queue.length >= this.maxSize) {
      await new Promise<void>((resolve) => this.waitersEnqueue.push(resolve));
    }
    this.queue.unshift(x);
    // 如果有等待出队的任务,唤醒第一个等待的请求
    if (this.waitersDequeue.length > 0) {
      const resolve = this.waitersDequeue.shift();
      resolve!();
    }
  }

  async dequeue(): Promise<T> {
    // 循环检查队列是否为空,直到有元素可取
    while (this.queue.length === 0) {
      await new Promise<void>((resolve) => this.waitersDequeue.push(resolve));
    }
    const item = this.queue.pop()!;
    // 如果有等待入队的任务,唤醒第一个等待的请求
    if (this.waitersEnqueue.length > 0) {
      const resolve = this.waitersEnqueue.shift();
      resolve!();
    }
    return item;
  }
}

async function produce<T>(q: AsyncQueue<T>, x: T) {
  await q.enqueue(x);
}

async function consume<T>(q: AsyncQueue<T>): Promise<T> {
  return await q.dequeue();
}

// 测试代码:先输出3、4,1秒后输出5、6
(async () => {
  const q = new AsyncQueue<number>();
  consume(q).then(console.log); // 等待元素,拿到3
  consume(q).then(console.log); // 等待元素,拿到4
  produce(q, 3);
  produce(q, 4);
  // 这两个consume会阻塞,直到有新元素入队
  consume(q).then(console.log);
  consume(q).then(console.log);
  // 延迟添加新元素测试后续等待逻辑
  setTimeout(() => {
    produce(q, 5);
    produce(q, 6);
  }, 1000);
})();

关键逻辑解释

  1. 等待队列的维护:当队列状态不满足操作条件时,我们创建一个未resolve的Promise,把它的resolve函数存入对应等待队列,然后await这个Promise——这会让当前的enqueue/dequeue函数暂停执行。
  2. 状态变化的唤醒:每当成功完成enqueue或dequeue操作后,检查对应等待队列是否有等待的任务,如果有就取出第一个resolve函数执行,让对应的暂停函数继续运行。
  3. 用while循环而非if:因为有可能在Promise被resolve后,队列状态又不满足条件了(比如多个生产者同时被唤醒,但队列又满了),所以需要再次检查队列长度,确保条件满足后再执行操作。

结论

仅用async/await(结合Promise)就完全能实现你要的异步有界队列阻塞逻辑,不需要额外的协程。这种实现方式是非阻塞的,不会卡住事件循环,在Node.js和浏览器环境都能正常工作。

内容的提问来源于stack exchange,提问作者Hugo Sereno Ferreira

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 04:13:36