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

使用Generator实现队列类遇问题:yield未等待Promise resolve

问题原因解析

你这段代码的核心问题在于Generator本身不会自动等待Promise完成,而且你用普通的for...of遍历Generator时,只是同步取出每个yield产出的Promise对象,根本不会等待这些Promise resolve,所以所有的广播任务会被一次性启动,完全达不到串行队列的效果。

具体来说:

  • processQueue是普通Generator函数,它每次yield的是runBroadcast返回的Promise,但Generator不会暂停等待这个Promise完成,只是把Promise抛出去就继续执行下一次循环了。
  • run方法里的for...of是同步遍历,拿到每个Promise后直接打印,不会等它resolve,自然也就实现不了串行执行的队列逻辑。
修复方案

要实现串行的Promise队列,你需要结合async/await来处理Generator产出的Promise,或者直接使用异步Generator配合for await...of循环。

方案一:手动迭代Generator并await每个Promise

修改run方法为async函数,手动控制Generator的迭代过程,每次拿到Promise后等待它resolve,再继续下一个:

class BroadcastQueueHandler {
  #broadcastQueue;
  #metaData;

  constructor() {
    this.#broadcastQueue = [];
  }

  setItems(aBroadcasts) {
    this.#broadcastQueue = aBroadcasts;
  }

  setMetaData(oMetaData) {
    this.#metaData = Object.assign({}, oMetaData);
  }

  runBroadcast(oBroadcast) {
    const oThis = this;

    return new Promise((resolve, reject) => {
      const aBroadcasts = [oBroadcast];
      const oBroadcastHandler = BroadcastHandler.factory(aBroadcasts);
      if (oBroadcastHandler !== null) {
        const oMetaData = Object.assign({}, oThis.#metaData);
        let fOnClick = function () {};

        if (typeof oMetaData.onClick === 'function') {
          fOnClick = oMetaData.onClick;
        }
        oMetaData.onClick = function () {
          fOnClick();
          resolve(oBroadcast);
        };

        oBroadcastHandler.setItems(aBroadcasts);
        oBroadcastHandler.setMetaData(oMetaData);
        oBroadcastHandler.run();
      }
    });
  }

  *processQueue() {
    for (const oBroadcast of this.#broadcastQueue) {
      yield this.runBroadcast(oBroadcast);
    }
  }

  async run() {
    const generator = this.processQueue();
    let result = generator.next();
    while (!result.done) {
      // 等待当前Promise resolve后再执行下一个
      await result.value;
      result = generator.next();
    }
  }
}

方案二:使用异步Generator + for await...of

把processQueue改成异步Generator函数(async function*),然后在run里用for await...of遍历,自动等待每个Promise完成:

class BroadcastQueueHandler {
  #broadcastQueue;
  #metaData;

  constructor() {
    this.#broadcastQueue = [];
  }

  setItems(aBroadcasts) {
    this.#broadcastQueue = aBroadcasts;
  }

  setMetaData(oMetaData) {
    this.#metaData = Object.assign({}, oMetaData);
  }

  runBroadcast(oBroadcast) {
    const oThis = this;

    return new Promise((resolve, reject) => {
      const aBroadcasts = [oBroadcast];
      const oBroadcastHandler = BroadcastHandler.factory(aBroadcasts);
      if (oBroadcastHandler !== null) {
        const oMetaData = Object.assign({}, oThis.#metaData);
        let fOnClick = function () {};

        if (typeof oMetaData.onClick === 'function') {
          fOnClick = oMetaData.onClick;
        }
        oMetaData.onClick = function () {
          fOnClick();
          resolve(oBroadcast);
        };

        oBroadcastHandler.setItems(aBroadcasts);
        oBroadcastHandler.setMetaData(oMetaData);
        oBroadcastHandler.run();
      }
    });
  }

  // 改为异步Generator函数
  async *processQueue() {
    for (const oBroadcast of this.#broadcastQueue) {
      // 等待当前任务完成后,再产出结果并执行下一个
      yield await this.runBroadcast(oBroadcast);
    }
  }

  async run() {
    // 使用for await...of遍历异步Generator,自动等待每个Promise完成
    for await (const result of this.processQueue()) {
      console.log('result', result);
    }
  }
}

这两种方案都能实现串行执行队列中的每个广播任务,只有当前任务的Promise resolve后,才会启动下一个任务。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 04:55:31