AngularJS - отказоустойчивость на $q.all()
Я пытаюсь заполнить некоторые локальные данные, разрешая серию удаленных вызовов.
Когда каждое обещание разрешено, я загружаю данные и продолжаю.
Метод $q.all( [] )
выполняет именно это:
$q.all([
this.getUserInfo(11)
.then(function (r) {
results.push(r)
}),
this.getUserConns()
.then(function (r) {
results.push(r)
}),
this.getUserCtxs()
.then(function (r) {
results.push(r)
})
])
.then(function () {
console.log(results)
})
Проблема в том, что этот код не является устойчивым.
Если любой из этих вызовов терпит неудачу, никто не получает рыбу!
Обертка вызовов в инструкции try/catch просто заставляет $q.all()
полностью игнорировать запись, даже если она не работает (обратите внимание на console.log в func)...
$q.all([
this.getUserInfo2(11)
.then(function (r) {
results.push(r)
}),
function () {
try {
this.getUserGroups()
.then(function (r) {
console.log(r)
results.push(r)
})
}
catch (err) {
console.log(err)
}
},
])
.then(function () {
console.log(results)
})
Вывод:
[Объект]
Любой намек на то, как я могу обернуть это, чтобы он был устойчивым?
Благодаря @dtabuenc, я сделал еще один шаг вперед.
Внедряя обратный вызов ошибки, я могу избежать разрыва цепи и нажать значения разрешенного promises.
Однако на консоли все еще отображается неприятное исключение...
Как я могу избавиться от этого, если я не могу попробовать/поймать асинхронные запросы?
Код вызывающего абонента
return $q.all([
this.getUserInfo(user_id)
.then(function (r) {
results['personal_details'] = r
}),
this.getUserConns()
.then(
function (r) {
results['connections'] = r
},
function(err) {
console.log(err)
})
])
.then(function () {
return (results)
})
Код Callee (ввод с исключением)
getUserConns: function() {
return __doCall( ws.getUserConnections, {} )
.then( function(r) {
// very generic exception injected
throw new Error
if (r && r.data['return_code'] === 0) {
return r.data['entries']
}
else {
console.log('unable to retrieve the activity - err: '+r.data['return_code'])
return null
}
})
},
Ответы
Ответ 1
Это будет работать, но также вытолкнуть ошибки в массив.
function push(r) {
results.push(r);
}
$q.all([
this.getUserInfo(11).then(push).catch(push),
this.getUserConns().then(push).catch(push),
this.getUserCtxs().then(push).catch(push)
])
.then(function () {
console.log(results);
})
Вы также должны улучшить свое понимание promises, вы никогда должны использовать try-catch
с promises - при использовании promises, вы используете метод .catch()
(со всем остальным неявно a try
). Это работает как для обычных ошибок, так и для асинхронных ошибок.
Если вы хотите полностью игнорировать ошибки:
function push(r) {
results.push(r);
}
function noop() {}
$q.all([
this.getUserInfo(11).then(push).catch(noop),
this.getUserConns().then(push).catch(noop),
this.getUserCtxs().then(push).catch(noop)
])
.then(function () {
console.log(results);
})
Ответ 2
Мне кажется, что это проще сделать:
$q.all([
mypromise1.$promise.catch(angular.noop),
mypromise2.$promise.catch(angular.noop),
mypromise1.$promise.catch(angular.noop)
])
.then(function success(data) {
//.....
});
Ответ 3
Я не уверен, что вы подразумеваете под устойчивым. Что вы хотите, если один из promises выходит из строя?
Ваш try-catch не будет работать, потому что обещание будет асинхронным.
Однако вы можете передать обработчик ошибок в качестве второго параметра в вызов then()
и делать все, что вы пожелаете.
Ответ 4
Такая же проблема. Для тех из вас, у кого есть петли: внутри ответа:
var tracks = [];
var trackDfds = [];
for(var i = 0; i < res.items.length; i++){
var fn = function () {
var promise = API.tracks(userId, res.items[i].id);
return promise.then(function (res) {
if (res.items.length) {
tracks.push(res.items);
}
}).catch(angular.noop);
};
trackDfds.push(fn());
}
$q.all(trackDfds)
.then(function (res) {
console.log(tracks);
});
Ответ 5
@Ответ на Esailija кажется обходным решением проблемы.
Вы не можете решить проблему вне основного источника проблемы: $q
.
Кажется немного мудрее иметь отклонения обратных вызовов для каждого then
(2-й аргумент) и там вставить $q.reject(...)
.
Пример:
$q.all([
this.getUserInfo(11).then(
function (response) { // UI data preparation for this part of the screen },
function (response) {
$q.reject(response);
}
),
// ...
])
.then(
function () {
// all good
},
function () {
// at least one failed
}
)
Это особенно заметно, когда модель пользовательского интерфейса зависит от всех вызовов ajax.
Лично я считаю, что это безопасный способ действовать в любом случае, потому что большую часть времени вы хотите направить некоторые серверные сообщения на какой-то компонент тоста на обратные вызовы отклонения или каким-то образом оповестить пользователя (очередь 7 вызовов ajax doesn 't означает, что вы ничего не можете показать, потому что 1 не удалось - это означает, что вы не сможете показать какую-либо область экрана - для этого нужна специальная обратная связь с пользователем).