web-dev-qa-db-fra.com

Abonnez-vous à plusieurs observables (comme l'enchaînement puis () dans Promises)

Mon Angular 2 possède 2 méthodes (GetCategories() et GetCartItems()) dans un service, et ces deux méthodes renvoient Observables.

Afin d'invoquer ces deux méthodes l'une après l'autre depuis mon composant, j'ai écrit ci-dessous le code:

 ngOnInit() 
{
   this.appService.GetCategories().subscribe( (data) => {
       this.appService.categories = data;


       this.appService.GetCartItems().subscribe( {
                                                    next: (data) => { this.appService.cart = data},
                                                    error: (err) => { this.toaster.error('cart==>' + err)}

                                                })

   });       
}

Fondamentalement, appeler GetCartItems() de l'intérieur subscribe() de GetCategories(), et je pense que ce n'est pas la bonne approche. C'est une sorte d'enfer de rappel.

Avez-vous une idée de la meilleure façon de l'implémenter (comme chaîner then() dans Promises)?

9
refactor

On dirait que GetCartItems ne dépend pas de GetCategories. Ensuite, vous pouvez utiliser Zip :

Observable
    .Zip(
        this.appService.GetCategories()
        this.appService.GetCartItems()
    )
    .catch(err => this.toaster.error(err))
    .subscribe(([categories, cartItems]) => {
        this.appService.categories = categories;
        this.appService.cart = cartItems;
    });
15
Sergey Sokolov

Cela se fait le plus souvent avec concat(), concatMap() ou éventuellement concatAll() selon votre cas d'utilisation et si vous devez appeler les deux services dans l'ordre ou non.

function GetCategories() {
    return Observable.timer(1000).do(() => console.log('GetCategories()'));
}

function GetCartItems() {
    return Observable.timer(1000).do(() => console.log('GetCartItems()'));
}

console.log('start...');

GetCategories()
  .concatMap(() => GetCartItems())
  .subscribe(() => console.log('done'));

Cela imprime sur la console:

start...
GetCategories()
GetCartItems()
done

Chaque élément est retardé pour montrer qu'ils sont appelés dans l'ordre l'un après l'autre.

Si vous n'avez pas besoin de conserver le même ordre, vous pouvez utiliser merge() ou mergeMap().

Voir la démo en direct: https://jsbin.com/wawajob/1/edit

Notez que l'utilisation de Zip() peut avoir un comportement indésirable. Voir https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/Zip.md

7
martin