RxJS:将源Observable分为3个或更多Observable的优雅方式

时间:2018-06-19 14:52:13

标签: javascript rxjs

我有一个套接字连接,它发出带有标识符的消息。我想为每种消息创建一个单独的可观察对象。我有一些解决方案,但它们都感觉笨拙或存在性能问题。我是RxJS的新手,所以我不知道我可能会遇到的陷阱。

我的第一个直觉是为每种类型创建一个可过滤的可观察对象:

const receive_message = Rx.fromEvent(socket, 'data').pipe(share());
const message_type_a = receive_message.pipe(filter(message => message.type === 'a'));
const message_type_b = receive_message.pipe(filter(message => message.type === 'b'));
const message_type_c = receive_message.pipe(filter(message => message.type === 'c'));
const message_type_d = receive_message.pipe(filter(message => message.type === 'd'));

我认为这会导致性能问题,因为每次收到任何消息时,它都会针对每种消息类型执行此检查。

我考虑过像这样进行多阶段分区:

const receive_message = Rx.fromEvent(socket, 'data');
const [message_type_a, not_a] = receive_message.pipe(partition(message => message.type === 'a'));
const [message_type_b, not_b] = not_a.pipe(partition(message => message.type === 'b'));
const [message_type_c, message_type_d] = not_b.pipe(partition(message => message.type === 'c'));

这太笨拙了,我不确定它的性能是否比过滤器解决方案还要强。

接下来,我尝试使用如下主题:

const message_type_a = new Rx.Subject();
const message_type_b = new Rx.Subject();
const message_type_c = new Rx.Subject();
const message_type_d = new Rx.Subject();

Rx.fromEvent(socket, 'data').subscribe(function (message) {
    switch (message.type) {
      case 'a':
        message_type_a.next(message);
        break;
      case 'b':
        message_type_b.next(message);
        break;
      case 'c':
        message_type_c.next(message);
        break;
      case 'd':
        message_type_d.next(message);
        break;
      default:
        console.log('Uh oh');
    }
  },
  console.log,
  function () {
    message_type_a.complete();
    message_type_b.complete();
    message_type_c.complete();
    message_type_d.complete();
  }
);

同样,这很笨拙,每当我使用主题时,我都会问自己这是否是“ Rx”的做事方式。

理想情况下,我可以执行以下操作:

const [
  message_type_a,
  message_type_b,
  message_type_c,
  message_type_d
] = Rx.fromEvent(socket, 'data').pipe(partitionMany(message.type));

那里是否有任何优雅的解决方案,或者像这样的根本性缺陷,我观察到的拆分源的整体方法是否可以观察到?

这是我的第一个问题,所以我希望我做得很好。提前致谢!

2 个答案:

答案 0 :(得分:0)

我将您的开关盒解决方案更改为性能更高的解决方案。

const message_type_a = new Rx.Subject();
const message_type_b = new Rx.Subject();
const message_type_c = new Rx.Subject();
const message_type_d = new Rx.Subject();

subjects = {
    'a': message_type_a,
    'b': message_type_b,
    'c': message_type_c,
    'd': message_type_d
}

Rx.fromEvent(socket, 'data').pipe(tap(message => 
subjects[message.type].next(message))).subscribe();

答案 1 :(得分:0)

请参见https://www.npmjs.com/package/rx-splice

我们有完全相同的情况,在我们的情况下,这确实是一个性能问题(使用node --perf进行了测量)。在阅读您的问题后,我才创建了此程序包,因为共享很重要。让我知道它是否对您有用!

请注意,只有在执行过滤器的选择器功能出现问题时才需要这样做!如拼接自述文件所述:

  

仅使用惯用的RxJS代码,对于   拼接的用例。但是,如果您正在编写高性能代码   上面观察到的输入$(或更可能是Subject)将是   订阅了hunderth或数千次(X),因此选择器   filter(fn)函数将被调用X次。这可以-并且   实际上确实证明了-成为我们最大的性能瓶颈   应用程序,所以我们编写了splice,它执行索引选择器   每个发射值只有一次。