Как отменить ожидающий запрос во внутреннем HTTP, наблюдаемом с RXJS?
Отмена ожидающего HTTP-запроса при изменении страницы
У нас есть служба Angular, которая имеет дорогой HTTP-запрос, доступ к которому могут получить 3 разных потребителя. Каждый потребитель может изменить этот запрос в любой момент, сделать новый запрос, и все другие потребители должны быть обновлены с новыми данными.
Поскольку подписки HTTP закрываются сразу после завершения, мы использовали внутреннюю наблюдаемую модель с субъектами поведения, чтобы поддерживать связь с потребителями (см. Ниже).
Проблема в том, что когда пользователь изменяет страницу, текущий ожидающий ответ HTTP не может быть отменен.
Обычно я не думаю, что было бы слишком большой проблемой выбрасывать HTTP-запрос в фоновом режиме... но помимо того, что это дорогостоящая операция, я обнаружил, что ожидающий ответ действительно разрешается после того, как пользователь вернулся обратно. на странице, он будет обновлять потребителей с данными для более старого запроса.
Нет Буэно.
Сервисный звонок
private dataSubject = new BehaviorSubject<MyData>(...);
public data$ = this.dataSubject.asObservable();
...
getData(): Observable<MyData> {
if (this.dataSubject)
return this.data$;
} else {
const http$ = this.http.post(...))
.pipe(map(response => response as MyData),
takeUntil(this.unsubscribe$)); // see tearDown() below
http$.subscribe(
(availableDevices: MyData) => {
this.dataSubject.next(availableDevices);
}
);
return this.data$;
}
}
Я попытался создать метод разрыва в службе, который каждый потребитель вызывает во время его вызова ngDestroy(), но он не работал, пока я не завершил поток. Но в тот момент я не смог перезапустить поток снова, когда пользователь вернулся на страницу.
tearDown(): void {
this.unsubscribe$.next();
this.unsubscribe$.complete();
// this.dataSubject.next(null);
// this.dataSubject.complete(); -- breaks
}
Я ни в коем случае не эксперт RXJS, поэтому не стесняйтесь указывать, если мой общий дизайн неверен. У меня есть подозрение, что я должен использовать switchMap() или share, чтобы два потребителя не делали один и тот же запрос; но поскольку этот наблюдаемый паттерн полужесткий, я не уверен, каков правильный курс действий. Не говоря уже о том, чтобы отменить его.
Любая помощь будет принята с благодарностью.
2 ответа
Самый простой способ отменить http-вызов - это отказаться от подписки.
const subscription: Subscription = this.http.post(...).subscribe(...);
subscription.unsubscribe();
Ваш teardown
Метод полезен и обычно используется как сборщик мусора и для отмены любых ожидающих наблюдений rxjs. Вы бы назвали это в ловушке service/component/directive ngOnDestroy, чтобы убедиться, что в памяти не осталось наблюдаемых.
Но если я правильно помню, угловой обрабатывает http-наблюдаемые, поэтому вам не нужно обрабатывать их. Вообще говоря, вам нужно только позаботиться о наблюдаемых вами самих, таких как ваши BehaviorSubject
,
Я решил это, используя Promises (асинхронные функции) с AbortSignal / AbortController, потому что в моем случае запрос http не был отменен, хотя тема была отменена. Может быть, я ошибся или это сработало бы сейчас. Тем не менее, Promises с AbortController делают эту работу тоже.
Смотрите здесь, как использовать AbortController. Однако при использовании AbortController может возникнуть проблема с совместимостью браузера.
Вы также можете конвертировать наблюдаемые в обещания с помощью.toPromise(), чтобы это не было проблемой.