web-dev-qa-db-fra.com

Comment fonctionne l'opérateur share () RxJs 5?

Ce n'est pas clair à 100% pour moi comment fonctionne l'opérateur RxJs 5 share(), voir ici le derniers documents . Jsbin pour la question ici .

Si je crée un observable avec une série de 0 à 2, chaque valeur séparée par une seconde:

var source = Rx.Observable.interval(1000)
.take(5)
.do(function (x) {
    console.log('some side effect');
});

Et si je crée deux abonnés à cet observable:

source.subscribe((n) => console.log("subscriptor 1 = " + n));
source.subscribe((n) => console.log("subscriptor 2 = " + n));

Je reçois ceci dans la console:

"some side effect ..."
"subscriptor 1 = 0"
"some side effect ..."
"subscriptor 2 = 0"
"some side effect ..."
"subscriptor 1 = 1"
"some side effect ..."
"subscriptor 2 = 1"
"some side effect ..."
"subscriptor 1 = 2"
"some side effect ..."
"subscriptor 2 = 2"

Je pensais que chaque abonnement souscrirait au même Observable, mais cela ne semble pas être le cas! C'est comme l'acte d'abonnement crée un observable complètement séparé!

Mais si l'opérateur share() est ajouté à la source observable:

var source = Rx.Observable.interval(1000)
.take(3)
.do(function (x) {
    console.log('some side effect ...');
})
.share();

Ensuite, nous obtenons ceci:

"some side effect ..."
"subscriptor 1 = 0"
"subscriptor 2 = 0"
"some side effect ..."
"subscriptor 1 = 1"
"subscriptor 2 = 1"
"some side effect ..."
"subscriptor 1 = 2"
"subscriptor 2 = 2"

C'est ce à quoi je m'attendrais sans la share().

Que se passe-t-il ici, comment fonctionne l'opérateur share()? Chaque abonnement crée-t-il une nouvelle chaîne Observable?

28
Angular University

Veillez à utiliser RxJS v5 alors que votre lien de documentation semble être RxJS v4. Je ne me souviens pas des détails mais je pense que l'opérateur share a subi quelques modifications, en particulier en ce qui concerne l'achèvement et la réinscription, mais ne prenez pas mon Word pour cela.

Revenons à votre question, comme vous l'avez montré dans votre étude, vos attentes ne correspondent pas à la conception de la bibliothèque. Les observables instancient paresseusement leur flux de données, initiant concrètement le flux de données lorsqu'un abonné s'abonne. Lorsqu'un deuxième abonné s'abonne au même observable, un autre nouveau flux de données est démarré comme s'il s'agissait du premier abonné (donc oui, chaque abonnement crée une nouvelle chaîne d'observables comme vous l'avez dit). C'est ce qui est inventé dans la terminologie RxJS comme observable à froid et c'est le comportement par défaut pour RxJS observable. Si vous voulez un observable qui envoie ses données aux abonnés qu'il a au moment où les données arrivent, il s'agit d'un observable à chaud, et une façon d'obtenir un observable à chaud consiste à utiliser l'opérateur share.

Vous pouvez trouver des abonnements illustrés et des flux de données ici: observables à chaud et à froid: y a-t-il des opérateurs "à chaud" et "à froid"? (ceci est valable pour RxJS v4, mais la plupart est valable pour v5) .

19
user3743222

part rend l'observable "chaud" si ces 2 conditions sont remplies:

  1. le nombre d'abonnés> 0
  2. ET l'observable n'est pas terminé

Scénario1: nombre d'abonnés> 0 et observable n'est pas terminé avant un nouvel abonnement

var shared  = rx.Observable.interval(5000).take(2).share();
var startTime = Date.now();
var log = (x) => (value) => { 
    console.log(`onNext for ${x}, Delay: ${Date.now() - startTime} , Value: ${value}`);
};

var observer1 = shared.subscribe(log('observer1')),
    observer2;

setTimeout(()=>{
    observer2 = shared.subscribe(log('observer2'));
}, 3000);

// emission for both observer 1 and observer 2, with the samve value at startTime + 5 seconds
// another emission for both observers at: startTime + 10 seconds

Scénario 2: le nombre d'abonnés est nul avant un nouvel abonnement. Devient "froid"

 var shared  = rx.Observable.interval(5000).take(2).share();
    var startTime = Date.now();
    var log = (x) => (value) => { 
    console.log(`onNext for ${x}, Delay: ${Date.now() - startTime} , Value: ${value}`);
};

var observer1 = shared.subscribe(log('observer1')),
    observer2;

setTimeout(()=>{
    observer1.unsubscribe(); 
}, 1000);

setTimeout(()=>{
    observer2 = shared.subscribe(log('observer2')); // number of subscribers is 0 at this time
}, 3000);
// observer2's onNext is called at startTime + 8 seconds
// observer2's onNext is called at startTime + 13 seconds

Scénario 3: quand observable a été achevé avant un nouvel abonnement. Devient "froid"

 var shared  = rx.Observable.interval(5000).take(2).share();
    var startTime = Date.now();
    var log = (x) => (value) => { 
        console.log(`onNext for ${x}, Delay: ${Date.now() - startTime} , Value: ${value}`);
    };

var observer1 = shared.subscribe(log('observer1')),
    observer2;

setTimeout(()=>{
    observer2 = shared.subscribe(log('observer2'));
}, 12000);

// 2 emission for observable 1, at startTime + 5 secs, and at startTime + 10secs
// 2 emissions for observable 2,at startTime + 12 + 5 secs, and at startTime + 12 + 10secs
13
sbr