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

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

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

原始代码看起来像这样:

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现在有异步迭代器,这应该使这成为可能。但是,在我已经有一个多次调用的回调的情况下,我无法理解我是如何使用异步迭代器的。

javascript callback generator
1个回答
3
投票

你可以使生成器async,然后await一个Promise,解析所有行(这样你就可以引用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
}

看起来.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;
  }
}

虽然,我不认为生成器在这里有很多帮助 - 你可能只是await一个解析为行的Promise,并同步迭代行:

function getRows(db, query) {
  return new Promise((resolve, reject) => {
    db.getAllRows(query, (err, rows) => {
      if (err) reject(err);
      else resolve(rows);
    });
  });
}

const rows = await getRows(...);
for (const row of rows) {
  // ...
}
© www.soinside.com 2019 - 2024. All rights reserved.