55

最近、リアクティブ プログラミングの概念に基づいて動作するRxJSおよび RxJava (Netflix の) ライブラリを調べ始めました。

Node.js は、イベント ループに基づいて動作します。イベント ループは、非同期プログラミングのためのすべての武器を提供し、「クラスター」などの後続のノード ライブラリは、マルチコア マシンを最大限に活用するのに役立ちます。また、Node.js は EventEmitter 機能も提供します。この機能では、イベントをサブスクライブして非同期で処理できます。

一方、私が正しく理解していれば、RxJS (および一般的なリアクティブ プログラミング) は、イベント ストリームの原則に基づいて動作し、イベント ストリームをサブスクライブし、イベント ストリーム データを非同期的に変換します。

そこで、問題は、Node.js で Rx パッケージを使用するとはどういう意味かということです。Node のイベント ループ、イベント エミッター、Rx のストリームとサブスクリプションに対するサブスクリプションの違い。

4

2 に答える 2

99

Observable は EventEmitters とは異なります。RxJSサブジェクトを使用してマルチキャストされる場合など、場合によっては EventEmitters のように動作することがありますが、通常は EventEmitters のようには動作しません

つまり、RxJS Subjectは EventEmitter に似ていますが、RxJS Observableはより一般的なインターフェースです。オブザーバブルは、引数がゼロの関数に似ています。

次の点を考慮してください。


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);

もちろん、出力として次のように表示されることを期待しています。

"Hello"
42
"Hello"
42

上記と同じ動作を記述できますが、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);
});

出力は同じです。

"Hello"
42
"Hello"
42

これは、関数と Observables の両方が遅延計算であるためです。関数を呼び出さないと、これconsole.log('Hello')は起こりません。また、Observable では、「呼び出し」( subscribe)を行わないと、このようなconsole.log('Hello')ことは起こりません。さらに、「呼び出し」または「サブスクライブ」は独立した操作です。2 つの関数呼び出しが 2 つの別個の副作用をトリガーし、2 つの Observable サブスクライブが 2 つの別個の副作用をトリガーします。副作用を共有し、サブスクライバーの存在に関係なく熱心に実行する EventEmitters とは対照的に、Observable は実行を共有せず、怠惰です。


これまでのところ、関数と Observable の動作に違いはありません。この StackOverflow の質問は、「RxJS Observables vs functions?」という表現の方が適切でしょう。

Observable は非同期であると主張する人もいます。そうではありません。関数呼び出しをログで囲むと、次のようになります。

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

明らかに出力が表示されます。

"before"
"Hello"
42
"after"

そして、これは Observables と同じ動作です:

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

そして出力:

"before"
"Hello"
42
"after"

fooこれは、関数のように、 のサブスクリプションが完全に同期的であることを証明しています。


では、Observable と関数の実際の違いは何でしょうか?

オブザーバブルは時間の経過とともに複数の値を「返す」ことができますが、機能することはできません。あなたはこれを行うことはできません:

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

関数は 1 つの値のみを返すことができます。ただし、オブザーバブルはこれを行うことができます。

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');

同期出力の場合:

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

しかし、値を非同期的に「返す」こともできます:

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);
});

出力あり:

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

結論として、

  • func.call()「すぐに(同期的に)1つの値を与える」ことを意味します
  • obsv.subscribe()値を教えてください。多分それらの多くは、おそらく同期的に、おそらく非同期的に

これが、Observables が関数 (引数を持たない) の一般化である方法です。

于 2016-02-06T09:04:19.497 に答える
11

リスナーが Emitter にアタッチされるのはいつですか?

イベント エミッターを使用すると、関心のあるイベントが発生するたびにリスナーに通知されます。イベントが発生した後に新しいリスナーが追加されると、彼は過去のイベントについて知りません。また、新しいリスナーは、以前に発生したイベントの履歴を知りません。もちろん、エミッターとリスナーを手動でプログラムして、このカスタム ロジックを処理することもできます。

リアクティブ ストリームを使用すると、サブスクライバーは最初から発生したイベントのストリームを取得します。そのため、彼が購読する時間は厳密ではありません。これで、ストリームに対してさまざまな操作を実行して、関心のあるイベントのサブストリームを取得できます。

これの利点は次のとおりです。

  • 時間の経過とともに発生したイベントを処理する必要がある場合
  • それらが起こった順序
  • イベントが発生したパターン (たとえば、Google 株のすべての購入イベントの後、Microsoft 株の販売イベントが 5 分以内に発生するとします)

高次ストリーム:

高次ストリームは「ストリームのストリーム」です。つまり、イベント値自体がストリームであるストリームです。

イベント エミッターを使用する方法の 1 つは、同じリスナーを複数のイベント エミッターにアタッチすることです。異なるエミッターで発生したイベントを関連付ける必要がある場合、複雑になります。

リアクティブ ストリームを使えば簡単です。mostjsの例(これは RxJS に似ていますが、よりパフォーマンスの高いリアクティブ プログラミング ライブラリです)

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

上記の例では、クリック イベントとマウス移動イベントを関連付けています。イベントがストリームとして利用可能になると、イベント間のパターンの推定が非常に簡単になります。

そうは言っても、EventEmitter を使用すると、エミッターとリスナーを過剰に設計することで、これらすべてを実現できます。そもそもこのようなシナリオを想定していないため、過剰なエンジニアリングが必要です。一方、リアクティブ ストリームは、このような問題を解決することを目的としているため、これを非常に流暢に行います。

于 2016-07-22T12:08:51.877 に答える