简体   繁体   English

反应式编程 - Node.js中的RxJS与EventEmitter

[英]Reactive Programming - RxJS vs EventEmitter in Node.js

Recently I've started looking at RxJS and RxJava(from Netflix) libraries which work on the concept of Reactive Programming. 最近我开始研究RxJS和RxJava(来自Netflix)的图书馆,这些图书馆致力于反应式编程的概念。

Node.js works on the basis of event loops, which provides you all the arsenal for asynchronous programming and the subsequent node libraries like "cluster" help you to get best out of your multi-core machine. Node.js基于事件循环工作,它为您提供了异步编程的所有工具,后续的节点库(如“cluster”)可帮助您充分利用多核机器。 And Node.js also provides you the EventEmitter functionality where you can subscribe to events and act upon it asynchronously. Node.js还为您提供了EventEmitter功能,您可以在其中订阅事件并以异步方式对其进行操作。

On the other hand if I understand correctly RxJS (and Reactive Programming in general) works on the principle of event streams, subscribing to event streams, transforming the event stream data asynchronously. 另一方面,如果我理解正确RxJS(和一般的反应式编程)工作原理事件流,订阅事件流,异步转换事件流数据。

So, the question is what does using Rx packages in Node.js mean. 所以,问题是在Node.js中使用Rx包是什么意思。 How different is the Node's event loop, event emitter & subscriptions to the Rx's streams and subscriptions. Node的事件循环,事件发射器和订阅Rx的流和订阅有多么不同。

Observables are not like EventEmitters. Observable与EventEmitters不同。 They may act like EventEmitters in some cases, namely when they are multicasted using RxJS Subjects, but usually they don't act like EventEmitters. 在某些情况下,它们可能像EventEmitters一样,即当它们使用RxJS主题进行多播时,但通常它们不像EventEmitters那样。

In short, an RxJS Subject is like an EventEmitter, but an RxJS Observable is a more generic interface. 简而言之,RxJS Subject就像一个EventEmitter,但RxJS Observable是一个更通用的接口。 Observables are more similar to functions with zero arguments. Observable更类似于零参数的函数。

Consider the following: 考虑以下:


function foo() {
  console.log('Hello');
  return 42;
}

var x = foo.call(); // same as foo()
console.log(x);
var y = foo.call(); // same as foo()
console.log(y);

Of course we all expect to see as output: 当然,我们都希望看到输出:

"Hello"
42
"Hello"
42

You can write the same behavior above, but with Observables: 您可以在上面编写相同的行为,但使用Observables:

var foo = Rx.Observable.create(function (observer) {
  console.log('Hello');
  observer.next(42);
});

foo.subscribe(function (x) {
  console.log(x);
});
foo.subscribe(function (y) {
  console.log(y);
});

And the output is the same: 输出是一样的:

"Hello"
42
"Hello"
42

That's because both functions and Observables are lazy computations. 那是因为函数和Observable都是惰性计算。 If you don't call the function, the console.log('Hello') won't happen. 如果不调用该函数,则不会发生console.log('Hello') Also with Observables, if you don't "call" ( subscribe ), the console.log('Hello') won't happen. 对于Observables,如果你不“调用”( subscribe ), console.log('Hello')将不会发生。 Plus, "calling" or "subscribing" is an independent operation: two function calls trigger two separate side effects, and two Observable subscribes trigger two separate side effects. 另外,“调用”或“订阅”是一个独立的操作:两个函数调用触发两个单独的副作用,两个Observable订阅触发两个单独的副作用。 As opposed to EventEmitters which share the side effects and have eager execution regardless of the existence of subscribers, Observables have no shared execution and are lazy. 与无论订阅者是否存在共享副作用并且急切执行的EventEmitters相反,Observables没有共享执行并且是懒惰的。


So far, no difference between the behavior of a function and an Observable. 到目前为止,函数和Observable的行为没有区别。 This StackOverflow question would have been better phrased as "RxJS Observables vs functions?". 这个StackOverflow问题可以更好地表达为“RxJS Observables vs functions?”。

Some people claim that Observables are asynchronous. 有些人声称Observables是异步的。 That is not true. 事实并非如此。 If you surround a function call with logs, like this: 如果您使用日志包围函数调用,如下所示:

console.log('before');
console.log(foo.call());
console.log('after');

You will obviously see the output: 您显然会看到输出:

"before"
"Hello"
42
"after"

And this is the same behavior with Observables: 这与Observables的行为相同:

console.log('before');
foo.subscribe(function (x) {
  console.log(x);
});
console.log('after');

And the output: 并输出:

"before"
"Hello"
42
"after"

Which proves the subscription of foo was entirely synchronous, just like a function. 这证明了foo的订阅完全是同步的,就像一个函数一样。


So what is really the difference between an Observable and a function? 那么Observable和函数之间真正区别的是什么呢?

Observables can "return" multiple values over time , something which functions cannot. Observable可以随时间“返回”多个值 ,而函数则不能。 You can't do this: 你不能这样做:

function foo() {
  console.log('Hello');
  return 42;
  return 100; // dead code. will never happen
}

Functions can only return one value. 函数只能返回一个值。 Observables, however, can do this: 但是,Observable可以这样做:

var foo = Rx.Observable.create(function (observer) {
  console.log('Hello');
  observer.next(42);
  observer.next(100); // "return" another value
  observer.next(200);
});

console.log('before');
foo.subscribe(function (x) {
  console.log(x);
});
console.log('after');

With synchronous output: 使用同步输出:

"before"
"Hello"
42
100
200
"after"

But you can also "return" values asynchronously: 但您也可以异步“返回”值:

var foo = Rx.Observable.create(function (observer) {
  console.log('Hello');
  observer.next(42);
  observer.next(100);
  observer.next(200);
  setTimeout(function () {
    observer.next(300);
  }, 1000);
});

With output: 随着输出:

"before"
"Hello"
42
100
200
"after"
300

To conclude, 总之,

  • func.call() means " give me one value immediately (synchronously) " func.call()表示“ 立即给我一个值(同步)
  • obsv.subscribe() means " give me values. Maybe many of them, maybe synchronously, maybe asynchronously " obsv.subscribe()意思是“ 给我价值。也许很多,也许是同步的,可能是异步的

That's how Observables are a generalization of functions (that have no arguments). 这就是Observables是函数的泛化(没有参数)。

When does a listener gets attached to Emitter ? 听众何时被附加到发射器?

With event emitters, the listeners are notified whenever an event, that they are interested in happens. 使用事件发射器,只要发生他们感兴趣的事件,就会通知侦听器。 When a new listener is added after the event has occurred, he will not know about the past event. 在事件发生后添加新的侦听器时,他将不知道过去的事件。 Also the new listener will not know the history of events that happened before. 此外,新的听众也不会知道之前发生的事件的历史。 Ofcourse, we could manually program our emitter and listener to handle this custom logic. 当然,我们可以手动编程我们的发射器和监听器来处理这个自定义逻辑。

With reactive streams, the subscriber gets the stream of events that happened from the beginning. 使用反应流,订户可以获得从一开始就发生的事件流。 So the time at which he subscribes is not strict. 所以他订阅的时间并不严格。 Now he can perform variety of operations on the stream to get the sub-stream of events that he is interested in. 现在,他可以在流上执行各种操作,以获得他感兴趣的事件子流。

The advantage of this comes out: 这样做的好处是:

  • when we need to process the events that happened over time 当我们需要处理随时间发生的事件时
  • order in which they happened 他们发生的顺序
  • patterns in which the events happened (Let's say, after every buy event on Google stock, a sell event on Microsoft stock happens within 5 minutes) 事件发生的模式(比方说,在谷歌股票的每次买入事件之后,微软股票的卖出事件发生在5分钟内)

Higher order streams: 更高阶的流:

A Higher-order stream is a "stream of streams": a stream whose event values are themselves streams. 高阶流是“流的流”:其事件值本身是流的流。

With Event emitters, one way of doing it is by having same listener attached to multiple event emitters. 使用Event发射器,一种方法是将相同的侦听器连接到多个事件发射器。 It becomes complex when we need to correlate the event happened on different emitters. 当我们需要关联不同发射器上发生的事件时,它变得复杂。

With reactive streams, it's a breeze. 使用反应流,这是一件轻而易举的事。 An example from mostjs (which is a reactive programming library, like RxJS but more performant) 来自mostjs的一个例子(这是一个反应式编程库,比如RxJS,但性能更高)

const firstClick = most.fromEvent('click', document).take(1);
const mousemovesAfterFirstClick = firstClick.map(() =>
    most.fromEvent('mousemove', document)
        .takeUntil(most.of().delay(5000)))

In the above example, we correlate the click events with mouse move events. 在上面的示例中,我们将点击事件与鼠标移动事件相关联。 Deducting patterns across events become so easier to accomplish when events are available as a stream. 当事件作为流可用时,跨事件的演绎模式变得更容易实现。

Having said that, with EventEmitter we could accomplish all this by over engineering our emitters and listeners. 话虽如此,通过EventEmitter,我们可以通过对发射器和侦听器进行过度设计来完成所有这些工作。 It needs over engineering because it is not intended in first place for such scenarios. 它需要过度工程,因为它不适用于这种情况。 Whereas reactive streams does this so fluently because it is intended to solve such problems. 尽管反应性流如此流畅地实现了这一点,因为它旨在解决这些问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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