SwitchMap vs MergeMap в примере #ngrx
Ниже приведен код из примера Ngrx: https://github.com/ngrx/example-app/blob/master/src/effects/book.ts Мой вопрос в том, почему в первом @Effect он использует switchMap
, в то время как другие используют mergeMap
. Это потому, что первый @Effect имеет дело с сетью, а с switchMap
вы можете отменить предыдущий сетевой запрос, если он работает?
@Effect() search$ = this.updates$
.whenAction(BookActions.SEARCH)
.map<string>(toPayload)
.filter(query => query !== '')
.switchMap(query => this.googleBooks.searchBooks(query)
.map(books => this.bookActions.searchComplete(books))
.catch(() => Observable.of(this.bookActions.searchComplete([])))
);
@Effect() clearSearch$ = this.updates$
.whenAction(BookActions.SEARCH)
.map<string>(toPayload)
.filter(query => query === '')
.mapTo(this.bookActions.searchComplete([]));
@Effect() addBookToCollection$ = this.updates$
.whenAction(BookActions.ADD_TO_COLLECTION)
.map<Book>(toPayload)
.mergeMap(book => this.db.insert('books', [ book ])
.mapTo(this.bookActions.addToCollectionSuccess(book))
.catch(() => Observable.of(
this.bookActions.addToCollectionFail(book)
))
);
@Effect() removeBookFromCollection$ = this.updates$
.whenAction(BookActions.REMOVE_FROM_COLLECTION)
.map<Book>(toPayload)
.mergeMap(book => this.db.executeWrite('books', 'delete', [ book.id ])
.mapTo(this.bookActions.removeFromCollectionSuccess(book))
.catch(() => Observable.of(
this.bookActions.removeFromCollectionFail(book)
))
);
}
Ответы
Ответ 1
Вы правы; switchMap
отменит подписку на Observable
, возвращенную ее аргументом project
, как только она снова вызовет функцию project
, чтобы создать новый Observable
.
RxJs невероятно мощный и плотный, но его высокий уровень абстракции иногда может затруднить понимание кода. Позвольте мне немного разоблачить мраморные диаграммы и документы, данные @Andy Hole, и привести их в актуальность. Вы можете найти описание синтаксиса мрамора, очень ценную для лучшего понимания операторов rxjs из их тестов (по крайней мере, я обнаружил, что это отсутствует/недостаточно выделено в официальные документы).
mergeMap
![mergeMap]()
Первая строка на диаграмме - это источник Observable, который испускает (1,3,5)
в разное время. Вторая строка на диаграмме представляет собой протопический Observable, возвращаемый функцией project
i => ...
, переданный оператору .mergeMap()
.
Когда источник Observable испускает элемент 1
, mergeMap()
вызывает функцию project
с помощью i=10
. Возвращаемый Observable будет излучать 10
три раза, каждые 10 кадров (см. ссылка на синтаксис мрамора). То же самое происходит, когда источник Observable испускает элемент 3
, а функция project
создает Observable, который испускает 30
три раза. Обратите внимание, что результат mergeMap()
содержит все три элемента, сгенерированные каждым наблюдаемым, возвращаемым из project
.
switchMap
Это отличается от switchMap()
, который отменит подписку на Observable, возвращенную project
, как только он снова вызовет ее в новом элементе. Мраморная диаграмма показывает это с отсутствующим третьим элементом 30
в выходном наблюдаемом.
В приведенном примере это приводит к отмене ожидающего запроса на поиск. Это свойство очень хорошее, но труднодоступное, которое вы получаете бесплатно, комбинируя switchMap()
с отменными Observables, возвращаемыми службой Angular Http
. Это может сэкономить много головных болей, не заботясь о правильном обращении со всеми условиями гонки, которые обычно происходят с асинхронной отменой.
Ответ 2
mergeMap
Проецирует каждое исходное значение на наблюдаемое, которое сливается в выходной Observable.
Сопоставляет каждое значение с наблюдаемым, затем выравнивает все эти внутренние наблюдаемые с помощью mergeAll.
![введите описание изображения здесь]()
switchMap
Проецирует каждое значение источника в наблюдаемое, которое объединяется в выходной элемент Observable, испуская значения только с самого последнего проецируемого Observable.
Сопоставляет каждое значение с наблюдаемым, затем выравнивает все эти внутренние наблюдаемые с помощью переключателя.
![введите описание изображения здесь]()
Источник: ES6 Observables в RxJS
Ответ 3
Вы правы.
Как вы можете видеть, switchMap используется с функцией поиска. Поиск в этом примере запрограммирован на то, чтобы в основном генерировать запрос на поиск, когда пользователь вводит текст в текстовое поле (с дебютом 350 мс или задержкой).
Это означает, что когда пользователь вводит "har", ngrx отправляет поисковый запрос службе. Когда пользователь вводит другую букву "r", предыдущий запрос отменяется (поскольку нас больше не интересует "har", а "harr" ).
Это очень хорошо показано на мраморных диаграммах, представленных в другом ответе.
В mergeMap предыдущие Observables не отменены, поэтому "30" и "50" смешиваются вместе. Используя switchMap, испускаются только 5s, потому что 3 отменены.