我有一个异步获取数据库行的函数,并为每一行调用一个回调函数。我正在尝试编写一个包装器,它是一个生成器函数,每次返回一行时都会生成,但我没有看到如何正确地生成。
原始代码看起来像这样:
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现在有异步迭代器,这应该使这成为可能。但是,在我已经有一个多次调用的回调的情况下,我无法理解我是如何使用异步迭代器的。
你可以使生成器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) {
// ...
}