这是在 angularfire2 中使用 rxjs MergeMap 的正确方法吗?

Is this the correct way to use rxjs MergeMap in angularfire2?

我是 angular 和 rxjs 的新手, 我正在尝试使用 angularfire2rxjsfirebase 获取三个不同的值,并将其作为承诺 return。经过多次研究和尝试,我终于使用这段代码成功了。

这是代码(假设 afdb 是 angularfire-database):

getThreeValues() {
    return this.afdb.list('firebaseref1').valueChanges().pipe(
        map(data => {
            return data.length;
        }),

        mergeMap(first => {
            return this.afdb.object('firebaseref2').valueChanges().pipe(
                map(second => {
                    return ({first: first, second: second})
                }),
                take(1)
            );
        }),

        mergeMap(firstsecond => {
            return this.afdb.list('firebaseref3').valueChanges().pipe(
                map(third => {
                    return ({...firstsecond, third: third})
                }),
                take(1)
            );
        }),

        take(1))
        .toPromise();
}

代码有效,我得到承诺,它解析为包含我需要的三个值的对象。

问题是我不确定这是否是最好的方法(因为我不确定这段代码是如何工作的)。

因为你很确定你只会取 .valueChanges() 的第一个值,所以将它们包装成 .forkJoin() 而不是全部 .mergeMapping 会更有效率方式。在 javascript 的 destructuring 的帮助下,您的代码可以看起来像这样简单得多:

getThreeValues() {
    return forkJoin(
        this.afdb.list('firebaseref1').valueChanges().pipe(take(1)),
        this.afdb.object('firebaseref2').valueChanges().pipe(take(1)),
        this.afdb.object('firebaseref3').valueChanges().pipe(take(1))
    )
        .pipe(
            map(([first, second, third]) => ({
                first: first.length,
                second,
                third
            }))
        ).toPromise()
}

好吧,你很有创意,很好地解决了这个问题,但还有更有效的方法。我不知道你是想 运行 并行查询还是串行查询,但由于你的代码没有表明这三个查询是相关的(第二个查询从第一个获取数据),我将提供一个并行解决方案,这应该可以更快地解决。

使用combineLatest

import { combineLatest } from 'rxjs';

// returns promise of [value1, value2, value3]
return combineLatest(
    this.afdb.list('firebaseref1').valueChanges().pipe(
        map(data => {
            return data.length;
        }),
        take(1),
    ),
    this.afdb.object('firebaseref2').valueChanges().pipe(
        take(1),
    ),
    this.afdb.object('firebaseref3').valueChanges().pipe(
        take(1),
    ),
).toPromise();

或更简单(更少代码)的解决方案(可能的结果略有不同):

import { combineLatest } from 'rxjs';
return combineLatest(
    this.afdb.list('firebaseref1').valueChanges().pipe(
        map(data => {
            return data.length;
        }),
    ),
    this.afdb.object('firebaseref2').valueChanges(),
    this.afdb.object('firebaseref3').valueChanges(),
).pipe(
    take(1),
).toPromise();

您也可以使用 forkJoin 实现此目的。

firstCall(){
  return this.afdb.list('firebaseref1').valueChanges().pipe(
    map(data => {
      return data.length;
    });
}

secondCall(){
  return this.afdb.object('firebaseref2').valueChanges().pipe(
        mergeMap(second => second),
        take(1)
      );
}

thirdCall(){
  return this.afdb.object('firebaseref3').valueChanges().pipe(
        mergeMap(third => third),
        take(1)
      );
}

const observables = [];
observables.push(this.firstCall());
observables.push(this.secondCall());
observables.push(this.thirdCall());

return forkjoin(observables).toPromise();