具有(a)同步功能的 Javascript 生成器

问题描述 投票:0回答:2

所以我一直在努力思考一个可能的解决方案,但我试图找出一个简单的例子却没有成功。

所以我有一组看起来像这样的数据:

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 () {}
}
];

我想创建一个生成器来遍历该数组但不返回(yield?)控制返回到下一次迭代,直到该回调函数被执行。我尝试将该回调包装在一个 promise 中,这样在执行该回调之前该 promise 不会解决。我试着确保回调是一个异步函数来包装那个承诺。我尝试了一些东西,但我就是无法让它们工作。在我调用生成器函数并遍历它之后,它只是遍历了数组的每个元素。无论我如何设置循环,它都不会在进入下一次迭代之前等待回调执行。

我四处搜索,但我发现的大多数关于生成器的例子以及它们如何与承诺(或异步函数)交互,这些例子只显示了这样的东西

yield Promise.resolve(x)
,这不是我想要的。我不希望它立即解决——我需要它等到
callback
被执行。并且回调将设置为 onclick 处理程序(以关闭对话框)并且仅在该事件发生时执行。所以基本上,在前一个对话框关闭之前,下一个对话框不应该实例化。

我如何最好地实现我想要实现的功能?正如我所说,我只是无法理解这个……

这是我写的一些代码的例子。当我尝试不同的事情时,这经历了几次变化。我在这里使用 fetch() 是因为我知道它会返回一个 Promise。我确信 Promises 需要在我的解决方案中的某个地方出现,以确保我的非异步

callback()
在控制继续之前执行。这很糟糕,但我只是在尝试不同的概念证明。

      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);
      }

谢谢,
克里斯托夫

javascript ecmascript-6 es6-promise
2个回答
1
投票

您可以使用异步迭代器

const arr = [{
  "content": "FIRST_CONTENT_HERE",
  "callback": function callback (_) { return _; }
},
{
  "content": "SECOND_CONTENT_HERE",
  "callback": function callback (_) { return _; }
},
{
  "content": "THIRD_CONTENT_HERE",
  "callback": function callback (_) { return Promise.resolve(_); }
},
{
  "content": "FOUR_CONTENT_HERE",
  "callback": function callback (_) { return _; }
}
];

async function* asyncGenerator(tasks) {
  for (const task of tasks) {
    yield task.callback(task.content);
  }
}

;(async function() {
  for await (const txt of asyncGenerator(arr)) {
    console.log('->', txt);
  }
})();


0
投票

Generators 和 Promises 有不同的目标

我想创建一个生成器来遍历该数组但不返回(yield?)控制权返回下一次迭代,直到执行该回调函数为止。

问题是生成器和 Promise 有根本不同的假设。 Promise 本质上是“我会一直致力于此,直到我完成,并在完成后给你回电”,而生成器本质上是“让我知道你何时准备好下一个”。

如果您使用的是生成器,那么您必须在下次调用该函数时返回一个值……您等不及了。所以问题是,等到第一个电话完成后再开始第二个电话对您来说有多重要?

如果你可以同时处理所有的调用,那么你的生成器可以只返回 Promise,你的调用代码可以负责

await
ing它们。

但是,如果按顺序一次处理一个标注很重要,则不能使用生成器。但是,您可以使用回调。

解决方案 1:使用回调参数保持控制

这可能不是完全你所希望的,但如果你必须确保一次按顺序调用一个标注,那么这是一个简单的解决方案。

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 () {}
}
];

async function processList(itemCallback) {
  for (const item of arr) {
    await item.callback();
    itemCallback(item);
  }
}

async function callingCode() {
  await processList(item => {
    // Do something with item...
  });
}

解决方案 2:通过返回 Promises 让调用者拥有控制权

如果生成器更多的是关于便利性和语法美感而不是性能或技术要求,那么您可以只返回 Promises 并让调用代码处理它们:

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

async function* getList() {
  for (const item of arr) {
    yield item.callback().then(() => item);
  }
}

async function callingCode() {
  for await (const item of getList()) {
    // Do something with item
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.