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

如何用JavaScript Generator实现等待回调执行后再迭代的功能?

问题描述

我一直尝试找解决方案,但写简单示例都没成功。我有如下格式的数组:

const arr = [{
  "content": "FIRST_CONTENT_HERE",
  "callback": function callback () {}
},
{
  "content": "SECOND_CONTENT_HERE",
  "callback": function callback () {}
},
{
  "content": "THIRD_CONTENT_HERE",
  "callback": function callback () {}
},
{
  "content": "THIRD_CONTENT_HERE",
  "callback": function callback () {}
}
];

我想创建一个Generator来遍历这个数组,但必须等当前元素的callback执行完成后,才进入下一次迭代。我试过把callback包装在Promise里,让它只在callback执行后才resolve;也试过把callback设为async函数来包装Promise,但都没成功——调用Generator后会直接遍历完所有数组元素,完全不会等待callback执行。

我查了相关资料,但大多数Generator和Promise/async函数结合的示例都是类似yield Promise.resolve(x)的形式,这不是我需要的——我不需要立即resolve,而是要等作为弹窗关闭onclick处理器的callback触发后才继续。也就是前一个弹窗关闭后,才实例化下一个弹窗。每轮迭代需要完成以下步骤:

  • 实例化一个弹窗
  • 为该弹窗设置onclick处理器,其中会执行callback()
  • 将callback包装为返回Promise的函数,仅在事件触发时才resolve,同时执行callback
  • Promise resolve后,Generator进入下一次迭代,实例化下一个弹窗,直到遍历完数组

我不确定自己的思路对不对,但我觉得Generator和Promise是可行的方向。请问该怎么实现这一功能?

以下是我尝试的代码(为验证概念做了多次修改,用fetch是因为它返回Promise):

async function runRequest(url) {
  const response = await fetch(url);

  return response;
}

async function* setupGenerator(arr) {
  for (let i = 0; i < arr.length; i++) {
    const response = await runRequest(arr[i]);
    yield response;
  }
}

const urls = [
  '/activityViewer/index.html',
  '/message/index.html',
  '/users/index.html',
];
debugger;
const generator = setupGenerator(urls);
for (let response of generator) {
    console.log('In FOR loop; response; ', response);
}

解决方案

你的核心思路是正确的,问题出在两个关键点:一是普通for...of无法处理异步Generator,需用for await...of;二是没有正确将弹窗关闭的用户交互事件包装为Promise,让Generator等待事件触发。

1. 封装弹窗与等待逻辑

先写一个工具函数,创建弹窗并返回Promise,仅在弹窗关闭(触发callback)时resolve:

function createPopupAndWait(content, callback) {
  return new Promise((resolve) => {
    // 模拟弹窗创建(替换为你实际的弹窗逻辑)
    const popup = document.createElement('div');
    popup.textContent = content;
    popup.style.padding = '20px';
    popup.style.border = '1px solid #ccc';
    popup.style.position = 'fixed';
    popup.style.top = '50%';
    popup.style.left = '50%';
    popup.style.transform = 'translate(-50%, -50%)';
    document.body.appendChild(popup);

    // 添加关闭按钮
    const closeBtn = document.createElement('button');
    closeBtn.textContent = '关闭';
    popup.appendChild(closeBtn);

    // 绑定关闭事件:执行callback -> 移除弹窗 -> 触发Promise resolve
    closeBtn.addEventListener('click', () => {
      callback();
      document.body.removeChild(popup);
      resolve();
    });
  });
}

2. 编写异步Generator

遍历数组时,等待当前弹窗的Promise完成后再进入下一轮迭代:

async function* popupGenerator(arr) {
  for (const item of arr) {
    await createPopupAndWait(item.content, item.callback);
    // 可根据需求yield当前迭代的结果,比如内容或索引
    yield `处理完成:${item.content}`;
  }
}

3. 执行Generator

用for await...of遍历异步Generator,确保每一步都等待前一个弹窗关闭:

async function runPopups() {
  const arr = [
    { content: '第一个弹窗', callback: () => console.log('第一个弹窗关闭') },
    { content: '第二个弹窗', callback: () => console.log('第二个弹窗关闭') },
    { content: '第三个弹窗', callback: () => console.log('第三个弹窗关闭') }
  ];

  const generator = popupGenerator(arr);
  for await (const result of generator) {
    console.log(result);
  }
}

// 启动执行
runPopups();

关键说明

  • 异步Generator与for await...of:普通for...of无法识别异步Generator的yield值,必须用for await...of才能等待每个Promise完成。
  • Promise封装用户交互:将弹窗关闭的点击事件作为Promise的resolve时机,确保Generator会等待用户操作完成后再继续。
  • callback执行顺序:先执行传入的callback再resolve Promise,保证callback完成后才进入下一轮迭代。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 05:03:28