有没有办法让Node.js作为协程流。
实施例 斐波纳契数字流。
fibonacci.on('data', cb);
//The callback (cb) is like
function cb(data)
{
//something done with data here ...
}
期望
function* fibonacciGenerator()
{
fibonacci.on('data', cb);
//Don't know what has to be done further...
};
var fibGen = fibonacciGenerator();
fibGen.next().value(cb);
fibGen.next().value(cb);
fibGen.next().value(cb);
.
.
.
从发电机中取出所需的数字。这里Fibonacci数字系列只是一个例子,实际上流可以是文件,mongodb查询结果等等。
也许是这样的
是否至少可能,如果是,如果不是为什么?也许是一个愚蠢的问题:)
答案 0 :(得分:6)
如果您不想使用转换器(例如Babel)或等到async
/ await
转到Node.js,您可以使用生成器和承诺自行实现它。
缺点是你的代码必须存在于生成器中。
首先,您可以创建一个接收流的帮助程序,并返回一个函数,该函数在调用时返回流的下一个“事件”的承诺(例如data
)。
function streamToPromises(stream) {
return function() {
if (stream.isPaused()) {
stream.resume();
}
return new Promise(function(resolve) {
stream.once('data', function() {
resolve.apply(stream, arguments);
stream.pause();
});
});
}
}
当你不使用它时它暂停流,并在你问下一个值时恢复它。
接下来,你有一个帮助器接收一个生成器作为参数,每次它产生一个promise,它会解析它并将其结果传递回生成器。
function run(fn) {
var gen = fn();
var promise = gen.next().value;
var tick = function() {
promise.then(function() {
promise = gen.next.apply(gen, arguments).value;
}).catch(function(err) {
// TODO: Handle error.
}).then(function() {
tick();
});
}
tick();
}
最后,您将在生成器中执行自己的逻辑,并使用run
帮助程序运行它,如下所示:
run(function*() {
var nextFib = streamToPromises(fibonacci);
var n;
n = yield nextFib();
console.log(n);
n = yield nextFib();
console.log(n);
});
run
函数。run
函数将解析承诺并将其值传递回您自己的生成器。这就是它的要点。您还需要修改streamToPromises
以检查其他事件(例如end
或error
)。
答案 1 :(得分:1)
class FibonacciGeneratorReader extends Readable {
_isDone = false;
_fibCount = null;
_gen = function *() {
let prev = 0, curr = 1, count = 1;
while (this._fibCount === -1 || count++ < this._fibCount) {
yield curr;
[prev, curr] = [curr, prev + curr];
}
return curr;
}.bind(this)();
constructor(fibCount) {
super({
objectMode: true,
read: size => {
if (this._isDone) {
this.push(null);
} else {
let fib = this._gen.next();
this._isDone = fib.done;
this.push(fib.value.toString() + '\n');
}
}
});
this._fibCount = fibCount || -1;
}
}
new FibonacciGeneratorReader(10).pipe(process.stdout);
1 1 2 3 5 8 13 21 34 55