взяв в качестве примера следующий код:
const subject$ = new Subject();
subject$
.pipe(
tap(() => console.info('tap1')),
switchMap(() => EMPTY),
tap(() => console.info('tap2')),
finalize(() => console.info('finalize')),
).subscribe();
subject$.next(null);
Я пытаюсь достичь следующего результата:
Expected Output:
tap1
finalize
Actual Output:
tap1
Чтение того, что делает каждый оператор, должно работать должным образом, но это не так.
Мой мыслительный процесс был:
tap2
не будут регистрироваться и finalize
будут регистрироваться, поскольку связанное наблюдаемое было завершено.Я явно не понимаю. Может ли кто-нибудь помочь мне понять поток и как заставить его работать для моих нужд, пожалуйста?
Пустое завершает, вы правы, но это завершит поток только тогда, когда EMPTY
будет началом потока!
EMPTY.pipe(finalize(() => console.info('finalize'))).subscribe({
next: () => console.info('Next'),
complete: () => console.info('Complete!'),
});
// will output
// Complete!
// finalize
Но нашим началом потока является subject$
, который еще не завершен и будет продолжать получать события, даже если середина потока остановлена на полпути EMPTY
, поэтому источник должен завершиться, тогда вы получите срабатывание финализации и завершения блока!
import './style.css';
import { Subject, switchMap, tap, finalize, EMPTY } from 'rxjs';
const subject$ = new Subject();
subject$
.pipe(
tap(() => console.info('tap1')),
switchMap(() => EMPTY),
tap(() => console.info('tap2')),
finalize(() => console.info('finalize'))
)
.subscribe({
next: () => console.info('next'),
error: () => console.info('error'),
complete: () => console.info('complete'),
});
// emits tap1
// output:
// tap1
subject$.next(null);
// emits tap 1 again eventhough empty was returned
// output:
// tap1
subject$.next(null);
// will complete the observable and give the output
// output:
// complete
// finalize
subject$.complete();
EMPTY.pipe(finalize(() => console.info('finalize'))).subscribe({
next: () => console.info('Next'),
complete: () => console.info('Complete!'),
});
// will output
// Complete!
// finalize
switchMap()
выдает complete
уведомление только тогда, когда завершается как объединенный Observable, так и исходный Observable.
Поскольку наверху вашей цепочки есть объект, который выдает complete
только тогда, когда вы вызываете complete()
функцию, switchMap()
никогда не завершится.
Более подробный пример: очень распространенный вариант использования switchMap()
— объединение асинхронного HTTP-запроса, например, в поле поиска с опережением ввода, например:
fromEvent(this.input.nativeElement, 'keyup')
.pipe(
map(event => event.target.value),
debounceTime(500),
switchMap(search => API call goes here),
)
.subscribe(res => {
console.info(res)
});
Если switchMap()
выдало complete
уведомление, когда его внутренний Observable завершился (то есть, когда завершился вызов API), то эта цепочка будет выполнять поиск только один раз. Однако fromEvent()
никогда не завершается, и поэтому, когда вы продолжаете вводить текст, он будет выполнять последующие вызовы API.
Спасибо. Я упустил тот факт, что исходный наблюдаемый объект также должен завершиться для завершения работы switchMap. Я хотел бы добавить, как я достиг своей цели (ожидаемого результата). Поскольку мой реальный вариант использования — это вызов, сделанный при отправке, в конечном итоге я использовал take(1), чтобы сделать наблюдаемый источник завершенным. Таким образом, когда я возвращаю EMPTY, код переходит непосредственно к финализации для очистки.