Подтвердить что ты не робот

RxJS продолжает прослушивание после ошибки Ajax

RxJs перестает слушать события щелчка при внутренних наблюдаемых ошибках (запрос Ajax). Я пытаюсь понять, как заставить прослушиватель событий подключиться к событию нажатия кнопки и изящно обрабатывать внутреннюю ошибку ajax.

Вот мой примерный код и ссылка на plunkr

var input = $("#testBtn");
var test = Rx.Observable.fromEvent(input,'click');

var testAjax = function() {
  return Rx.Observable.range(0,3).then(function(x){ 
    if(x==2)throw "RAWR"; //Simulating a promise error.
    return x;
  });
}

test.map(function(){
  return Rx.Observable.when(testAjax());
})
.switchLatest()
.subscribe(
  function (x) {
      console.log('Next: ', x);
  },
  function (err) {
      console.log('Error: ' + err);   
  },
  function () {
      console.log('Completed');   
  });

http://plnkr.co/edit/NGMB7RkBbpN1ji4mfzih

4b9b3361

Ответ 1

Вы можете использовать оператор catch (или псевдоним catchException), чтобы улавливать и обрабатывать ошибки, которые происходят в наблюдаемом, чтобы подписчики не были уведомлены об ошибке.

Игнорировать ошибки:

return Rx.Observable
    .when(testAjax())
    .catch(Rx.Observable.empty()); // continues with an empty obs after error.

Ошибки обработки:

var empty = Rx.Observable.return('default value');
return Rx.Observable
    .when(testAjax())
    .catch(function (error) {
        console.log('error:', error);
        return empty;
    });

Ответ 2

Я столкнулся с моими проблемами, интерпретируя, как это работает (и onErrorResumeNext). Борьба, с которой я столкнулся, заключалась в том, с каким контекстом применяется улов (или возобновление следующего). Простой разговорный перевод, который имеет для меня смысл, таков:

Учитывая поток (или наблюдаемый) наблюдаемых, catch (или onErrorResumeNext) будет потреблять ошибку и позволить вам предоставить один или несколько наблюдаемых для продолжения исходного потока.

Отбросьте ключ, чтобы исходный источник был прерван и заменен наблюдаемыми (-ами), которые вы предоставляете в функции catch/onErrorResumeNext. Это означает, что если у вас есть что-то вроде этого:

var src = Rx.Observable
    .interval(500)
    .take(10)
    .select(function(x) {
        if (x == 5) {
            return Rx.Observable.throw('Simulated Failure');
        }

        return Rx.Observable.return(x * 2);
    })

Тогда добавление .catch(Rx.Observable.return('N/A')) или .onErrorResumeNext(Rx.Observable.return('N/A')) на самом деле не приведет к продолжению вашего потока (полученному с помощью interval), а скорее закончит поток с окончательным наблюдаемым (N/A).

Если вы хотите обработать неудачу изящно и продолжить исходный поток, вам нужно что-то большее, как .select(function(x) { return x.catch(Rx.Observable.return('N/A')); }). Теперь ваш поток заменит любой наблюдаемый элемент в потоке, который завершится неудачей с уловленным значением по умолчанию, а затем продолжит работу с существующим исходным потоком.

var src = Rx.Observable
    .interval(500)
    .take(10)
    .select(function(x) {
        if (x == 5) {
            return Rx.Observable.throw('Simulated Failure');
        }

        return Rx.Observable.return(x * 2);
    })
    //.catch(Rx.Observable.return('N/A'))
    //.onErrorResumeNext(Rx.Observable.return('N/A'))
    .select(function(x) { return x.catch(Rx.Observable.return('N/A')); })
    .selectMany(function(x) { return x; });


var sub = src.subscribe(
    function (x) { console.log(x); },
    function (x) { console.log(x); },
    function () { console.log('DONE'); }
);

// OUTPUT:
// 0
// 2
// 4
// 6
// 8
// N/A
// 12
// 14
// 16
// 18
// DONE

Вот JSFiddle, который показывает это в действии.

Ответ 3

Я все еще немного смутился, пробовав принятый ответ, так что это то, что закончилось для меня. Это то, что у меня было:

  Rx.Observable.fromEvent(emitter, events.SUBMIT_EVENT)
      .flatMapFirst(email=>{
        return $.ajax({
          method: "POST",
          url: '/email',
          data: {
            email: email
          },
        }).promise()
      })
      .subscribe(response=>{
        if (response) {
          //do your success thing here
            }
          },
         error =>{
           //do your error thing
          }
         )

Когда сервер вернул ошибку (например, когда пользователь уже ввел свой адрес электронной почты), я не смог снова прослушать форму электронной почты пользователя. Это то, что сработало для меня:

  Rx.Observable.fromEvent(emitter, events.SUBMIT_EVENT)
      .flatMapFirst(email=>{
        return $.ajax({
          method: "POST",
          url: '/email',
          data: {
            email: email
          },
        }).promise()
      })
      .doOnError(error=> {
        //do your error thing here
      })
      .retry()
      .subscribe(response=>{
        if (response) {
          //do your success thing here
        }
      })