web-dev-qa-db-ja.com

複数のオブザーバブルをサブスクライブする(Promiseでthen()をチェーンするなど)

私のAngular 2アプリケーションには、サービス内に2つのメソッド(GetCategories()およびGetCartItems())があり、これらのメソッドの両方がObservablesを返します。

これらの2つのメソッドをコンポーネントから次々に呼び出すために、以下のコードを記述しました。

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

                                                })

   });       
}
_

基本的に、GetCartItems()subscribe()内からGetCategories()を呼び出すと、これは適切なアプローチではないと思います。これは一種のコールバック地獄です。

これをより良い方法で実装する方法についてのアイデア(Promisesでのthen()の連鎖など)?

9
refactor

GetCartItemsGetCategoriesに依存していないようです。次に、 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

これは最も一般的にconcat()concatMap()、または最終的にはconcatAll()を使用して行われます。

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

これはコンソールに出力されます:

_start...
GetCategories()
GetCartItems()
done
_

各アイテムは、これらが順番に呼び出されることを示すために遅延されます。

同じ順序を維持する必要がない場合は、merge()またはmergeMap()を使用できます。

ライブデモをご覧ください: https://jsbin.com/wawajob/1/edit

Zip()を使用すると、望ましくない動作が発生する可能性があることに注意してください。 https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/Zip.md を参照してください

7
martin