繁体   English   中英

如何将节点可读 stream 转换为 RX 可观察

[英]How to convert node readable stream to RX observable

如果我有一个 Node.js stream,例如来自process.stdinfs.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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM