Как использовать retryWhen с функцией, которая возвращает логическое значение?

#angular #rxjs #rxjs5 #angular2-observables

#angular #rxjs #rxjs5 #angular2-наблюдаемые

Вопрос:

Вот мой код:

 this._http.post(this._url_get   extension, '', { headers: headers })
    .map(res => res['_body'])
    .retryWhen(errors => {return responseErrorProcess(errors)})
  

теперь мне нужно перехватывать исключения и передавать их в my, responseErrorProcess() который возвращает true , если требуется повторить попытку

Я не мог понять, как извлекать исключения из errors , вот как это выглядит:

 Subject_isScalar: falseclosed: falsehasError: falseisStopped: falseobservers: Array[0]thrownError: null__proto__: Observable`
  

Похоже, что она не содержит ошибок о возникающих исключениях, плюс я не мог понять, что я должен вернуть, чтобы на самом деле повторить попытку или нет.

Ответ №1:

retryWhen должно возвращать наблюдаемое. Повторная попытка происходит, как только наблюдаемый выдает:

 .retryWhen(errors => 
    //switchMap to retrieve the source error
    errors.switchMap(sourceErr => 
        //send source to processor
        responseErrorsProcess(sourceErr) ? 
        //if result is TRUE, emit (will cause retry). Else, pass on the error
        Observable.of(true): Observable.throw(sourceErr)
    )
)
  

Если вы хотите завершить вместо ошибки при возврате вашего процессора false , замените Observable.throw() на Observable.empty()

Ответ №2:

Вызываемое в retryWhen() должно возвращать наблюдаемое, которое выдает complete или error для завершения потока или выдает значение для повторной подписки.

Например, этот код завершается без выдачи ошибки из-за Observable.empty() :

 Observable.create(obs => {
    obs.next(1);
    obs.next(2);
    obs.error('error from source');
  })
  .retryWhen((errors) => {
      errors.subscribe(sourceError => console.log(sourceError));
      return Observable.create(obs => obs.error('inner error'));
  })
  .subscribe(
    val => console.log(val),
    err => console.log('error', err),
    _ => console.log('complete')
  );
  

Ошибка из наблюдаемого источника передается в errors как next . Смотрите исходный код:https://github.com/ReactiveX/rxjs/blob/master/src/operator/retryWhen.ts#L86

Это выводится на консоль:

 1
2
error inner error
error from source
  

Смотрите живую демонстрацию:http://plnkr.co/edit/Fajsb54WJwB8J8hkUC6j?p=preview

Редактировать на основе комментариев ниже:

Посмотрите документацию для retryWhen() :

Ошибка вызовет выдачу Throwable, которая вызывает ошибку для Observable, возвращаемого из notificationHandler. Если это наблюдаемое вызывает onComplete или error, то повторная попытка вызовет complete или error для дочерней подписки. В противном случае это наблюдаемое значение будет повторно подписано на исходное наблюдаемое значение в конкретном планировщике.

Таким образом, наблюдаемая величина, возвращаемая при обратном вызове, отвечает за принятие решения о повторной подписке. Если он выдает next() , то повторите подписку. Если оно выдает error() или complete() передает их дочернему наблюдателю.

Например, вы могли бы сделать (я не тестировал этот код):

 return response.retryWhen((errors) => {
    var retrySource = new Subject();
    errors.subscribe(error => {
        if (this.responseErrorProcess(error)) retrySource.next();
        else retrySource.complete();
    });
    return retrySource;
});
  

В соответствии с вашей внутренней логикой вы запускаете правильное сообщение на retrySource .

Комментарии:

1. Спасибо! но как получить ошибки? вы видите, ошибка, которую мы получаем подобным образом, является наблюдаемой и на самом деле не содержит исключения, не та ошибка, которую я бы получил с помощью .catch(), которая на самом деле содержит http-ответ (извините за мой слабый способ объяснения)

2. @MotassemMK Смотрите мой обновленный ответ. Это работает точно так, как это задокументировано в reactivex.io/rxjs/class/es6 /… . Тем не менее, я согласен, что описание очень часто бывает очень запутанным.

3. что ж, отлично, я получил ошибки! но (и, извините, это второй последующий вопрос) как я могу вернуть значение retryWhen изнутри flatMap как его асинхронное? это то, что я пробовал:

4. @MotassemMK Я обновил свой ответ, посмотрите внизу.

5. @MotassemMK Ты прав, используй subscribe() вместо flatMap