将多次调用的回调转换为生成器函数

时间:2019-03-10 21:35:10

标签: javascript callback generator

我有一个异步获取数据库行的函数,并为每行调用一个回调函数。我正在尝试编写一个包装器,该包装器是一个生成器函数,每次返回一行时都会产生收益,但是我没有看到如何正确产生收益。

原始代码如下:

db.each(query, (err, row) => {
  // do something here with row
}, () => {
  // called after the last row is returned
})

我熟悉生成器的工作原理,但是收益似乎属于生成器函数本身,而不是匿名函数。因此,我认为类似的方法将无效:

function* dbEach(db, query) {
    db.each(query, (err, row) => {
      yield row
    })
}

当我实际尝试 时,出现错误“意外标识符”。

我进一步看了一下,看来ES2018现在具有异步迭代器,应该可以实现这一点。但是,在我已经有多次被调用的回调的情况下,我难以理解如何正确使用异步迭代器。

1 个答案:

答案 0 :(得分:3)

您可以使生成器async,然后使await成为所有行都可以解析的Promise(这样,您就可以在{{1}的顶层引用一个rows变量}),然后可以产生该dbEach数组中的每一行:

rows

用于:

async function* dbEach(db, query) {
  const rows = await new Promise((resolve, reject) => {
    const rows = [];
    db.each(query, (err, row) => {
      if (err) reject(err);
      else rows.push(row);
    }, () => resolve(rows));
  });
  for (const row of rows) {
    yield row;
  }
}

for await (const row of dbEach(...)) { // do something } 似乎是为在每一行上运行一个回调而设计的,这对于使用生成器在此处尝试完成的操作而言并不是最佳选择-如果可能的话,如果有数据库中的一种方法,该方法可让您获取行的 array ,例如:

.each

尽管如此,我认为生成器在这里没有多大帮助-您最好async function* dbEach(db, query) { const rows = await new Promise((resolve, reject) => { db.getAllRows(query, (err, rows) => { if (err) reject(err); else resolve(rows); }); }); for (const row of rows) { yield row; } } 一个Promise解析为行,并同步遍历行:

await