[英]How to convert node readable stream to RX observable
如果我有一个 Node.js stream,例如来自process.stdin
或fs.createReadStream
类的东西,我如何使用 RxJs5 将其转换为 RxJs Observable stream?
我看到RxJs-Node有一个fromReadableStream
方法,但看起来它已经将近一年没有更新了。
对于任何寻找这个的人,按照 Mark 的建议,我为 rxjs5 调整了 rx-node fromStream
实现。
import { Observable } from 'rxjs';
// Adapted from https://github.com/Reactive-Extensions/rx-node/blob/87589c07be626c32c842bdafa782fca5924e749c/index.js#L52
export default function fromStream(stream, finishEventName = 'end', dataEventName = 'data') {
stream.pause();
return new Observable((observer) => {
function dataHandler(data) {
observer.next(data);
}
function errorHandler(err) {
observer.error(err);
}
function endHandler() {
observer.complete();
}
stream.addListener(dataEventName, dataHandler);
stream.addListener('error', errorHandler);
stream.addListener(finishEventName, endHandler);
stream.resume();
return () => {
stream.removeListener(dataEventName, dataHandler);
stream.removeListener('error', errorHandler);
stream.removeListener(finishEventName, endHandler);
};
}).share();
}
请注意,它本质上打破了流的所有背压功能。 Observables 是一种推送技术。 所有输入块都将被读取并尽快推送给观察者。 根据您的情况,它可能不是最佳解决方案。
以下内容适用于 v4 和 v5(免责声明未经测试):
fromStream: function (stream, finishEventName, dataEventName) {
stream.pause();
finishEventName || (finishEventName = 'end');
dataEventName || (dataEventName = 'data');
return Observable.create(function (observer) {
// This is the "next" event
const data$ = Observable.fromEvent(stream, dataEventName);
// Map this into an error event
const error$ = Observable.fromEvent(stream, 'error')
.flatMap(err => Observable.throw(err));
// Shut down the stream
const complete$ = Observable.fromEvent(stream, finishEventName);
// Put it all together and subscribe
const sub = data$
.merge(error$)
.takeUntil(complete$)
.subscribe(observer);
// Start the underlying node stream
stream.resume();
// Return a handle to destroy the stream
return sub;
})
// Avoid recreating the stream on duplicate subscriptions
.share();
},
上面的答案将起作用,尽管不支持背压。 如果您尝试使用 createReadStream 读取大文件,它们将读取内存中的整个内容。
这是我的背压支持实现: rxjs-stream
RxJs-Node 实现基于 RxJs4,但无需太多工作即可移植到 RxJs5 https://github.com/Reactive-Extensions/rx-node/blob/87589c07be626c32c842bdafa782fca5924e749c/index.js#L52
由于 Node v11.14.0 流支持for await
https://nodejs.org/api/stream.html#stream_readable_symbol_asynciterator
这意味着您可以将流传递给from()
运算符。
在引擎盖下 rxjs(v7.xx) 将调用fromAsyncIterable()
将返回Observable
最近来到这里的任何人(RxJS 7 和 Node 18+)都应该使用以下代码。
为什么这行得通? RxJS 已更新为处理 stream 类对象。 当您将 ReadStream 传递给 RxJS 时,它会测试它是否为ReadableStreamLike
,然后将其转换为AsyncGenerator
。
import { from } from 'rxjs';
const file = fs.createReadStream(fileName);
const file$ = from(file).subscribe({
next: (dat) => { ... },
error: (err) => { ... },
complete: () => { ... }
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.