web-dev-qa-db-fra.com

RXJS Attend que tous les éléments observables d'un tableau soient terminés (ou erronés)

Je pousse observables dans un tableau comme celui-ci ...

var tasks$ = [];
tasks$.Push(Observable.timer(1000));
tasks$.Push(Observable.timer(3000));
tasks$.Push(Observable.timer(10000));

Je veux un observable qui émet quand toutes les tâches sont terminées. Gardez à l'esprit que, dans la pratique, les tâches $ n'ont pas un nombre connu d'observables.

J'ai essayé Observable.Zip(tasks$).subscribe() mais cela semble échouer dans le cas où il n'y aurait qu'une seule tâche et me porte à croire que Zip nécessite un nombre pair d'éléments pour fonctionner de la manière que j'attendais. 

J'ai essayé Observable.concat(tasks$).subscribe() mais le résultat de l'opérateur concat semble être un tableau d'observables ... par exemple. fondamentalement la même chose que l'entrée. Vous ne pouvez même pas appeler vous abonner à ce sujet.

En C #, cela ressemblerait à Task.WhenAll(). Dans ES6, cela ressemblerait à Promise.all().

J'ai rencontré un certain nombre de SO questions, mais elles semblent toutes traiter de l'attente d'un nombre connu de flux (par exemple, en les cartographiant ensemble). 

33
josh-sachs

Si vous souhaitez composer un observable qui émet une fois que tous les observables sources sont terminés, vous pouvez utiliser forkJoin:

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/forkJoin';
import 'rxjs/add/operator/first';

var tasks$ = [];
tasks$.Push(Observable.timer(1000).first());
tasks$.Push(Observable.timer(3000).first());
tasks$.Push(Observable.timer(10000).first());
Observable.forkJoin(...tasks$).subscribe(results => { console.log(results); });
61
cartant

Vous pouvez utiliser Zip.

Combine plusieurs observables pour créer un observable dont les valeurs sont calculées à partir des valeurs, dans l'ordre, de chacun des observables en entrée.

const obsvA = this._service.getObjA();
const obsvB = this._service.getObjB();
// or with array
// const obsvArray = [obsvA, obsvB];

const Zip = Observable.Zip(obsvA, obsvB);
// or with array
// const Zip = Observable.Zip(...obsvArray);
Zip.subscribe(
  result => console.log(result), // result is an array with the responses [respA, respB]
);

Choses à considérer:

  • N'a pas besoin d'être un nombre pair d'observables.
  • Zip visuellement
  •  enter image description here Comme dit ici ,

    L'opérateur Zip souscrira à toutes les observables internes en attendant que chacune émette une valeur. Une fois que cela se produit, toutes les valeurs avec l'index correspondant seront émises. Cela continuera jusqu'à ce qu'au moins un observable interne soit terminé.

  • Lorsque l'un des observables génère une erreur (ou même les deux), l'abonnement est fermé (onComplete on complete est appelé) et avec une méthode onError, vous obtenez uniquement la première erreur.
  • Zip.subscribe(
      result => console.log(result), // result is an array with the responses [respA, respB]
      error => console.log(error), // will return the error message of the first observable that throws error and then finish it
      () => console.log ('completed after first error or if first observable finishes)
    );
    
    3
    João Ghignatti

    Pour moi, ce échantillon était la meilleure solution.

    const source = Observable.interval(500);
    const example = source.sample(Observable.interval(2000));
    const subscribe = example.subscribe(val => console.log('sample', val));
    

    Donc .. seulement quand second (exemple) émet - vous verrez la dernière valeur émise de premier (source).

    Dans ma tâche, j'attends la validation du formulaire et tout autre événement DOM.

    0