У меня есть служба angular, которой принадлежит Observable. У меня есть несколько (переменное количество) компонентов, подписанных на него, которые реагируют на выполнение асинхронных операций. Мне нужно, чтобы мой сервис знал, когда закончились все эти асинхронные операции с компонентами.
Это подход к моей ситуации:
Служба фильтрации
...
appliedFilter$: Observable<FormattedFilter[]> = new Observable<FormattedFilter[]>(
o => (this.appliedFilter = o)
).pipe(shareReplay(1));
private appliedFilter: Observer<FormattedFilter[]>;
onFiltersApplied(filters: Filter[]): void {
if (this.appliedFilter) {
const formattedFilters = this.formatFilters(filters);
this.appliedFilter.next(formattedFilters);
}
}
...
Фильтруемый компонент 1
...
this.filterService.appliedFilter$.subscribe(filters => {
// multiple pipelined async operations
});
...
Фильтруемый компонент 2
...
this.filterService.appliedFilter$.subscribe(filters => {
// multiple pipelined async operations
});
...
Фильтруемый компонент 3
...
this.filterService.appliedFilter$.subscribe(filters => {
// multiple pipelined async operations
});
...
Итак, что мне нужно, так это служба фильтров, чтобы заметить, когда все компоненты применили полученные фильтры через applyFilter$ Observable и когда все отфильтрованные данные наконец загружены.
Цель этого состоит в том, чтобы запретить пользователю обновлять фильтры до того, как все компоненты завершат процесс фильтрации.
Спасибо!
@ArtemArkhipov У меня нет особой потребности. Ваш подход кажется хорошим. Но я не знаю, как отменить текущие обновления, поскольку они могут быть довольно сложными.
Я разместил ответ для вас ниже
Спасибо, попробую.
Если бы вы могли создать минимальную копию вашего случая, вам было бы легче помочь и показать что-то конкретное.
Я обновил свой ответ еще одним примером, дайте мне знать, если это помогло.
@ maxime1992 maxime1992 У меня нет репродукции, потому что я нахожусь на этапе проектирования. Итак, что лучше всего соответствует моим потребностям, так это концептуальный ответ.
@ArtemArkhipov Я дам вам знать в ближайшие дни. Спасибо!
@Mochics хорошо, но тогда не могли бы вы рассказать немного больше о том, чего именно вы пытаетесь достичь? «Цель этого состоит в том, чтобы запретить пользователю обновлять фильтры до того, как все компоненты завершат процесс фильтрации», мне не совсем понятно.
@ maxime1992 Дело в том, что у меня есть несколько фильтров, которые можно комбинировать, и все эти фильтры обновляют несколько компонентов. Моя цель состояла в том, чтобы заблокировать функцию фильтрации, пока не будут разрешены все ожидающие асинхронные операции. Это оказалось не лучшим подходом, так как, на мой взгляд, АртемАрхипов указал на лучший вариант, заключающийся в отмене всех ожидающих запросов, если выбран новый фильтр. Надеюсь, теперь мои намерения раскрыты.
О, я вижу, спасибо. Да, ответ Артема кажется подходящим!
@maxime1992 Все равно спасибо!
@ArtemArkhipov Это работает. Хороший подход, спасибо!
Вы уверены, что вам нужно подождать, пока компоненты будут обновлены, вместо того, чтобы обновлять компоненты соответственно, чтобы отфильтровать изменения? В большинстве хороших, удобных приложений подход выглядит иначе: Если какой-то компонент не завершил обновление во время применения нового фильтра - обновления просто отменяются и запускаются заново.
В вашем случае это можно сделать с помощью оператора rxjs переключательКарта. Этот оператор позволяет вам делать именно то, что я только что сказал — отказаться от текущих асинхронных операций и начать новые, если появится новый выброс.
Вот пример:
...
this.filterService.appliedFilter$
.pipe(
switchMap(
filters => { return yourObservableChain()} // chain is your async opeartions
)
)
.subscribe(); // you have only the most relevant values here
...
Итак, что здесь происходит:
yourObservableChain
(это может быть http-запрос или любые другие вещи, которые вы имели в виду, когда говорили (асинхронные операции).subscribe
придет только самый актуальный результат.Примечание, этот switchMap должен возвращает наблюдаемое. Вот еще один короткий пример его использования в рамках Angular (с вызовами http).
import { switchMap } from 'rxjs/operators'; // don't forget
... your components code:...
this.triggerSubject$.pipe( // assume this emits with some urls
switchMap(data => { // assume new url is a prop of data
return this.http.get(data.URL); // returns observable
})
).subscribe(results => {
// having only fresh results here
// because switchMap cancelled other requests
console.info(results) // or do whatever you need
})
Вы уверены, что вам нужно подождать, пока компоненты будут обновлены, вместо того, чтобы обновлять компоненты соответственно, чтобы отфильтровать изменения? Так что, если какой-то компонент не обновился при применении нового фильтра - пусть он просто отменит текущие обновления и сделает новый. Так обычно работают хорошие приложения.