Programmation réactive-RxJS vs EventEmitter dans le noeud.js

3 réponses

vous avez raison que RX streams et EventEmitter sont très similaires, les deux sont des implémentations du pattern Observer.

la différence est que Rx contient des fonctions pour transformer et combiner les flux d'événements. Imaginez par exemple que nous voulions retarder chaque "événement de réponse" de 2 secondes. Avec EventEmitter, vous devez vous abonner à cela, et faire manuellement un timeout:

eventEmitter.on('response', function(res) {
    setTimeout(function() { /* handle res */ }, 2000);
});

Avec Rx, vous pouvez créer un flux d'événements qui est simplement le flux d'origine appliqué à la fonction de temporisation:

responseStream.delay(2000).subscribe(function(res) {
    /* handle res */
});

delay() est une fonction simple, et l'un des beaucoup d'autres sont disponibles. Il y a tellement de façons différentes de modifier les flux, qu'il devient possible de programmer beaucoup de logique d'application juste en transformant les flux avec toutes les fonctions possibles, au lieu de compter sur une logique de bas niveau comme setTimeout.

vérifiez aussi cette exploration visuelle et interactive de ces fonctions.

39
répondu André Staltz 2014-08-16 13:40:10

ma réponse ~il y a deux ans était fausse et je ne peux pas la modifier ou la supprimer de façon significative. les Observables ne sont pas comme les EventEmitters. Ils loi comme les EventEmitters dans certains cas, notamment lorsqu'ils sont multicastés en utilisant des sujets RxJS, mais habituellement ils n'agissent pas comme des EventEmitters.

en bref, un RxJS Sujet est comme un EventEmitter, mais un RxJS Observables est une interface plus générique. Observables sont plus similaires aux fonctions avec zéro argument.

Considérons le code suivant:


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

bien sûr, nous attendons tous de voir en sortie:

"Hello"
42
"Hello"
42

vous pouvez écrire le même comportement ci-dessus, mais avec 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);
});

Et le résultat est le même:

"Hello"
42
"Hello"
42

c'est parce que les fonctions et les Observables sont des calculs paresseux. Si vous ne faites pas appel de la fonction, le console.log('Hello') n'arrivera pas. Aussi avec Observables, si vous ne "appelez" pas (subscribe),console.log('Hello') n'arrivera pas. De plus, "appeler" ou "s'abonner" est une opération indépendante: deux appels de fonction déclenchent deux effets secondaires distincts, et deux abonnés observables déclenchent deux effets secondaires distincts. Contrairement aux EventEmitters qui partagent les effets secondaires et ont une exécution impatiente indépendamment de l'existence d'abonnés, les Observables n'ont pas d'exécution partagée et sont paresseux.


pour l'instant, aucune différence entre le comportement d'une fonction et D'un Observable. Cette question aurait été mieux formulée comme suit: "RxJS Observables vs functions?".

certaines personnes prétendent que les Observables sont asynchrones. Ce n'est pas vrai. Si vous entourez un appel de fonction avec des logs, comme ceci:

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

il faudra bien entendu voir le résultat:

"before"
"Hello"
42
"after"

Et c'est le même comportement avec Observables:

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

et le sortie:

"before"
"Hello"
42
"after"

ce qui prouve la souscription de foo était entièrement synchrone, comme une fonction.


alors quelle est vraiment la différence entre une fonction Observable et une fonction?

Observables peut "retourner" plusieurs valeurs au fil du temps, quelque chose qui fonctionne pas. Vous ne pouvez pas faire ceci:

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

les Fonctions ne peuvent retourner une valeur. Observables, cependant, peuvent faire ceci:

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

avec sortie synchrone:

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

mais vous pouvez aussi "retourner" des valeurs asynchrones:

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

sortie:

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

Pour conclure,

  • func.call() signifie "donne-moi une valeur immédiatement (de façon synchrone)"
  • obsv.subscribe() signifie "donnez-moi des valeurs. Peut-être beaucoup d'entre eux, peut-être synchrones, peut-être de façon asynchrone"

C'est ainsi que les Observables sont une généralisation des fonctions (qui n'ont pas d'arguments).

74
répondu André Staltz 2016-02-06 10:50:46

Quand un auditeur obtient attaché à l'Émetteur ?

avec les émetteurs d'événements, les auditeurs sont avertis chaque fois qu'un événement, qu'ils sont intéressés se produit. Lorsqu'un écouteur est ajouté après l'événement, il ne va pas connaître le passé de l'événement. Aussi le nouvel auditeur ne connaîtra pas l'histoire des événements qui se sont produits avant. Bien sûr, nous pourrions programmer manuellement notre émetteur et notre auditeur pour gérer cette logique personnalisée.

Avec réactif les ruisseaux, l'abonné reçoit le flux d'événements qui s'est passé depuis le début. Donc, l'heure à laquelle il a souscrit n'est pas stricte. Maintenant, il peut effectuer diverses opérations sur le stream pour obtenir le sous-flux d'évènements qu'il est intéressé.

L'avantage de ce sort:

  • lorsque nous avons besoin pour traiter les événements qui ont eu lieu au fil du temps
  • ordre dans lequel ils se sont produits
  • les modèles dans lesquels les événements se sont produits ( par exemple, après chaque événement d'achat sur Google stock, un événement de vente sur Microsoft stock se produit dans les 5 minutes)

ordre Supérieur flux:

un flux D'ordre supérieur est un "flux de flux": un flux dont les valeurs d'événements sont elles-mêmes des flux.

avec les émetteurs D'Événements, une façon de le faire est d'avoir le même récepteur attaché aux émetteurs d'événements multiples. Il devient complexe lorsque nous avons besoin de corréler l'événement s'est produit sur différentes émetteur.

avec des courants réactifs, c'est une brise. Un exemple de mostjs (qui est une bibliothèque de programmation réactive, comme RxJS mais plus performante)

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

dans l'exemple ci-dessus, nous corrélons les événements de clic avec les événements de déplacement de la souris. Déduire les modèles à travers les événements devient tellement plus facile à accomplir quand les événements sont disponibles comme un flux.

cela dit, avec EventEmitter, nous pourrions accomplir tout cela en émetteurs et auditeurs. Il a besoin de plus d'ingénierie parce qu'il n'est pas prévu en premier lieu pour de tels scénarios. Tandis que les flux réactifs le font si couramment parce qu'il est destiné à résoudre de tels problèmes.

0
répondu Sairam Krish 2016-07-22 12:23:53