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