Это правильный способ использовать rxjs MergeMap в angularfire2? - PullRequest
0 голосов
/ 13 ноября 2018

Я новичок в angular и rxjs, я пытаюсь получить три разных значения из firebase, используя angularfire2 и rxjs, и вернуть его как обещание.После нескольких исследований и попыток я, наконец, сделал это с помощью этого кода.

Вот код (предполагая, что 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();
}

Код работает, и я получаю обещание, которое преобразуется в объект, который содержит три значения, которые мне нужны.

Проблема в том, что я не уверен, что это лучший способ (поскольку я не уверен, как работает этот код).

Ответы [ 3 ]

0 голосов
/ 13 ноября 2018

Что ж, вы проявили творческий подход и решили проблему очень хорошо, но есть более эффективные способы сделать это.Я не знаю, хотите ли вы выполнять запросы параллельно или последовательно, но так как ваш код не предполагает, что три запроса являются зависимыми (второй берет данные из первого), я предоставлю параллельное решение, которое должно бытьбыстрее решить.

Использование 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();
0 голосов
/ 13 ноября 2018

Вы можете достичь этого, используя 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();
0 голосов
/ 13 ноября 2018

Поскольку вы абсолютно уверены, что вы примете только первое значение вашего .valueChanges(), гораздо эффективнее будет заключить их в .forkJoin() вместо .mergeMapping. С помощью destructuring из javascript ваш код может выглядеть намного проще, как это:

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()
}
...