RxJS. Тонкость работы iif
iif принимает функцию-условие и 2 необязательных Observable. Роль iif заключается в том, чтобы подписаться на один из Observable. В простых случаях все работает ожидаемо:
import { iif, of, pipe } from 'rxjs';
import { mergeMap } from 'rxjs/operators';
const source$ = of('Hello');
source$.pipe(
mergeMap(v =>
iif(
() => v === 'Hello',
of('first').pipe(tap(x => console.log(`>>> ${x} <<<`))),
of('second').pipe(tap(x => console.log(`>>> ${x} <<<`))),
))
).subscribe(console.log);
// >>> first <<<
// firstПроблема может возникнуть, если использовать оператор для задачи отправки http-запросов (2 и 3 аргумент iif) в зависимости от результата функции-условия т.е. если вернулось true, то сделать первый запрос, если false - второй.
iif(
() => Boolean(condition),
this.httpRequestOne(),
this.httpRequestTwo()
)В действительности будут выполнены оба запроса, но в поток вернётся результат только одного. Такое поведение можно проиллюстрировать следующим примером:
import { iif, of, pipe } from 'rxjs';
import { mergeMap } from 'rxjs/operators';
const source$ = of('Hello');
const obsOne$ = (x) => {console.log(`${x} World`); return of('One')};
const obsTwo$ = (x) => {console.log(`${x}, Goodbye`); return of('Two')};
source$.pipe(
mergeMap(v =>
iif(
() => v === 'Hello',
obsOne$(v),
obsTwo$(v)
))
).subscribe(console.log);Будет выведено
Hello World
Hello, Goodbye # ВНЕЗАПНО
OneРешением будет использовать оператор defer вместо iif.
defer(() => (
Boolean(condition)
? this.httpRequestOne()
: this.httpRequestTwo()
))