Я работаю над преобразованием устаревшего API на основе обратных вызовов в асинхронную библиотеку.Но я просто не могу обернуться, заставляя «набор результатов» работать как генератор (Узел 10.x).
Исходный API работает так:
api.prepare((err, rs) => {
rs.fetchRows(
(err, row) => {
// this callback is called as many times as rows exist
console.log("here's a row:", row);
},
() => {
console.log("we're done, data exausted");
}
);
});
НоВот как я хочу его использовать:
const wrapped = new ApiWrapper(api);
const rs = await wrapped.prepare({});
for (let row of rs.rows()) {
console.log("here's a row:", row);
}
let row;
while(row = await rs.next()) {
console.log("here's a row:", row);
}
Я думал, что у меня это под контролем генераторов, но похоже, что вы не можете использовать yield
внутри обратного вызова.Это на самом деле кажется логичным, если подумать.
class ApiWrapper {
constructor(api) {
this.api = api;
}
prepare() {
return new Promise((resolve, reject) => {
this.api.prepare((err, rs) => {
if (err) {
reject(err);
} else {
resolve(rs);
}
});
});
}
*rows() {
this.api.fetchRows((err, row) => {
if (err) {
throw err;
} else {
yield row; // nope, not allowed here
}
});
}
next() { ... }
}
Итак, какие у меня есть альтернативы?
Важно : я не хочу ничего хранить в массивезатем повторим это, мы говорим о гигабайтах данных строк.
Edit Я могу смоделировать поведение, которое я хочу, используя stream.Readable
, но оно предупреждает меня, что этоэкспериментальная особенность.Вот упрощенная версия проблемы, которую я пытаюсь решить, используя stream
:
const stream = require('stream');
function gen(){
const s = new stream.Readable({
objectMode: true,
read(){
[11, 22, 33].forEach(row => {
this.push({ value: row });
});
this.push(null)
}
});
return s;
}
for await (let row of gen()) {
console.log(row);
}
// { value: 11 }
// { value: 22 }
// { value: 33 }
(node:97157) ExperimentalWarning: Readable[Symbol.asyncIterator] is an experimental feature. This feature could change at any time