Проблема
Вы хотите опросить свой API, пока не будут возвращены определенные статусы. Если возвращается статус opened
или closed
, вы хотите повторить запрос. Если возвращается статус payed
, used
или что-то еще, вы хотите, чтобы ваш компонент выполнил действие.
Проблема с вашей реализацией
Вы создаете много вложенных подписки, что вообще плохая идея. Должен быть один подписчик верхнего уровня - все остальное можно связать в цепочку как наблюдаемые.
Мой дизайн
Я бы сначала попытался удалить все вложенные подписки. Затем я хотел бы использовать оператор expand
для рекурсивного связывания наблюдаемой - об этом позаботился опрос.
Я собираюсь создать тип Status
для строгой типизации.
Функция getStatus
вернет Observable<Status>
, так как нет необходимости возвращать полный ответ.
В целях ответа я собираюсь упростить то, что вы делаете. Это может означать, что я удаляю функциональность, которую вы хотите, но я собираюсь сосредоточиться в основном на аспекте опроса. После этого вы сможете добавить дополнительные функции обратно.
Моя реализация
status
export type Status = 'open' | 'closed' | 'payed' | 'used' | 'error';
service
private continuePollingStatuses: Status[] = [
'open', 'closed'
];
getIntervalStatus(sessionId: string): Observable<Status> {
return this.getStatus(sessionId).pipe(
expand((status: Status) => {
if (this.continuePollingStatuses.includes(status)) {
// repeat the request
return this.getStatus(sessionId);
}
// do not repeat the request
return empty();
}),
catchError((err) => of('error'))
);
}
private getStatus(sessionId: string): Observable<Status> {
// cache-busting query param
const timestamp = new Date().getTime();
const url = `${this.fullWsUrl}/Payment/GetPaymentStatus?t=${timestamp}`;
const httpParams = new HttpParams().set('sessionId', sessionId);
const options = { observe: 'response', params: httpParams };
return this.http.post<string>(url, null, options).pipe(
map(response => response.body.toLowerCase())
);
}
component
ngOnInit() {
const sessionId = this.printerVMService.getSessionId();
this.service.getIntervalStatus(sessionId).pipe(
switchMap((status: Status) => this.performAction(status))
).subscribe(status => {
this.status = status;
switch (this.status) {
case 'opened':
case 'closed':
case 'used':
break;
case 'payed':
this.localStorageService.storePaymentIsMade(true);
this.router.navigate(['welcome/paying/paying_accepted']);
break;
case 'error':
console.error(this.translate.instant('PAYMENT.DEVICE.GETSTATUSERRORMSG'));
this.utils.deleteSectionAction(this.printerVMService.getPrinterVM());
break;
default:
console.error('status don\'t exist');
this.utils.deleteSectionAction(this.printerVMService.getPrinterVM());
}
});
}
private performAction(status: Status): Observable<Status> {
switch (status) {
case 'payed':
return this.dbService.addOrderPaymentResult(ProcessResult.done,
this.printerVMService.getSessionId()).pipe(
map(() => of(status))
);
}
return of(status);
}
ДЕМО: https://stackblitz.com/edit/angular-7gkixg