Ошибка iphone: подписка на наблюдаемое возвращает мне первое выпущенное значение, - PullRequest
0 голосов
/ 06 марта 2020

Можете ли вы сказать мне, если проблема в этом коде. Я пытаюсь настроить опрос данных. ответы, следующие за ответом на первый запрос, не передаются на сервер, и все наблюдаемые мной значения имеют то же значение, что и первый ответ. это даже если состояние изменяется в серверной части.

Пример Если самый первый getStatus возвращает открытый, следующие запросы не передаются, и наблюдаемые ответы будут открыты

в моей службе i в моем компоненте есть следующий код

getIntervalStatus(sessionId: string): Observable<HttpResponse<string>> {

    return this.getStatus(sessionId).pipe(
      map(
        (result: HttpResponse<string>) => {
          this.statusOpened = result.body.toLowerCase();
          this.utils.alertLog(this.getStatus, result.body.toLowerCase());
          this.statusEmit.next(this.statusOpened);
          if (this.statusOpened === 'opened' || this.statusOpened === 'closed') {
            this.getIntervalStatus(sessionId).subscribe( );
          }
          return result;
        }
      ),
      catchError((err) => {
        this.statusOpened = 'error';
        this.utils.alertLog(this.getStatus, JSON.stringify(err));
        this.statusEmit.error(err);
        throw err;
      })
    );

  }

getStatus(sessionId: string): Observable<HttpResponse<string>> {
    const httpParams = new HttpParams().set('sessionId', sessionId);
    return this.http.post<string>(this.fullWsUrl + '/Payment/GetPaymentStatus', null,
      { observe: 'response', params: httpParams }).pipe(
         map((value: HttpResponse<string>) => {
          this.utils.alertLog(this.getStatus, value.status.toString());
          return value;
        })
      );
  } 

у меня есть следующий код


      this.openSessionSubscription = this.device.openSession(amount, this.printerVMService.getSessionId()).subscribe(
        data => {
          this.utils.alertLog(this.device.getIntervalStatus, 'Session is opened');
          this.sessionIsOpened = true;
          // subject for information session is opened
          this.device.statusOpened = 'opened';

          this.device.statusEmit = new Subject<string>();
          this.statusEmitSubscriber = this.device.statusEmit.subscribe(
            status => {

              this.status = status;
              console.log(this.constructor.name + 'payment status', this.status);
              switch (this.status) {
                case 'opened':
                  break;
                case 'payed':
                  this.utils.alertLog(this.device.getIntervalStatus, 'statut payed');
                  this.localStorageService.storePaymentIsMade(true);
                  this.dbService.addOrderPaymentResult(ProcessResult.done, this.printerVMService.getSessionId()).subscribe();
                  this.router.navigate(['welcome/paying/paying_accepted']);
                  break;
                case 'closed':
                  this.utils.alertLog(this.device.getIntervalStatus, 'statut closed');
                  // this.paymentSessionIsClosed = true;
                  // this.dbService.addOrderPaymentResult(ProcessResult.error, this.printerVMService.getSessionId()).subscribe();
                  // this.utils.deleteSectionAction(this.printerVMService.getPrinterVM());
                  break;
                case 'used':
                  this.utils.alertLog(this.device.getIntervalStatus, 'status used');
                  // this.utils.deleteSectionAction(this.printerVMService.getPrinterVM());
                  break;
                default:
                  console.error('status don\'t exist');
                  this.utils.alertLog(this.device.getIntervalStatus, 'statut not exist');
                  this.utils.deleteSectionAction(this.printerVMService.getPrinterVM());
              }
            },
            error => {
              this.alert.success('statut error');
              console.error(this.translate.instant('PAYMENT.DEVICE.GETSTATUSERRORMSG'));
              this.utils.deleteSectionAction(this.printerVMService.getPrinterVM());
            }
          );

          this.utils.alertLog(this.device.getIntervalStatus, 'getIntervalStatusSubscription is call');
          this.getIntervalStatusSubscription = this.device.getIntervalStatus(this.printerVMService.getSessionId()).subscribe();

        },
        error => {
          // emit session not open
          console.error(this.translate.instant('PAYMENT.DEVICE.OPENERRORMSG'));
          this.utils.alertLog(this.device.openSession, 'open error');
          this.utils.deleteSectionAction(this.printerVMService.getPrinterVM());
        }
      );

1 Ответ

1 голос
/ 07 марта 2020

Проблема

Вы хотите опросить свой 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

...