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
Ответы
Ответ 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
}
})