RxJS 序列的更好方法

Better way of RxJS Sequence

如何简化这个序列,因为我似乎在重新创建厄运金字塔,应该有更多的 Rx-y 方式。

public isEligibleForOffers(): Observable<Boolean> {
    return Observable.create((observer) => {
        this.getAccounts().subscribe(
            (accounts) => {
                if (!this.accountsAreInCredit(accounts)) {
                    observer.next(false);
                } else {
                    this.getOffers(accounts).subscribe(
                        (data: Offers) => {
                            let isEligible = (data.eligible && this.eligibleForAny(data) === true && this.registeredForAny(data) !== true);
                            observer.next(isEligible);
                        }
                    );
                }
            });
    });
}

我需要打一个 XHR 电话来获取帐户集合,如果帐户有信用,再打一个 XHR 电话来获取当前优惠,如果用户有资格获得任何优惠 return真否则假。

基本上

我问的和我在 SO 上看到的有两个区别:

另一个类似的情况可能是 (1) 获取令牌,然后 (2) 在后续请求中使用令牌。

如果要链接可观察对象,请使用 switchMapflatMap。此外,您不需要使用 Observable.create() 故意创建另一个 Observables,因为您的 this.getAccounts() 已经返回一个 observable。

这应该更简洁:

public isEligibleForOffers(): Observable<Boolean> {
    return this.getAccounts().switchMap(accounts => {
        if (this.accountsAreInCredit(accounts)) {
            return this.getOffers(accounts)
                .map((data: Offers) => {
                    return (data.eligible && this.eligibleForAny(data) === true && this.registeredForAny(data) !== true);
                })
        }
        //you can be explicit by returning a an Observable of false:
        return Obersvable.of(false);
    })
}

你可以像这样使用它:

this.isEligibleForOffers()
    .subscribe(flag => {
        //flag is a boolean
        if(flag){
            //do something
        }else{
            //do something else
        }
    })

给出的签名:

getAccounts(): Account[]
accountsAreInCredit(accounts: Account[]): boolean
getOffers(accounts: Account[]): Offers

您可以按如下方式对函数建模:

public isEligibleForOffers(): Observable<Boolean> {
  return this.getAccounts()
    .filter(accounts => this.accountsAreInCredit(accounts))
    .mergeMap(
      accounts => this.getOffers(accounts),
      (accounts, offers) => offers.eligible && this.eligibleForAny(offers) && !this.registeredForAny(offers))
    )
    .concat(Rx.Observable.of(false))
    .take(1);
  }  

因此,如果 accountsAreInCredit 产生 false,流将变为空,然后我们使用 .concat 运算符将默认值 false 附加到流。

mergeMap(又名 flatMap)接受一个 optional argument resultSelector,您可以在其中映射输出值,因此我们将它们映射到 isEligibleForOffers 布尔值。

然后最后通过限制函数 isEligibleForOffers 可以产生的值的数量,我们防止我们自己发出 true(来自 mergeMap)和 false(默认来自 concat) 作为排放量。