Que se passe-t-il avec $ q.all () lorsque certains appels fonctionnent et que d'autres échouent?
J'ai le code suivant:
var entityIdColumn = $scope.entityType.toLowerCase() + 'Id';
var requests = $scope.grid.data
.filter(function (rowData, i) {
return !angular.equals(rowData, $scope.grid.backup[i]);
})
.map(function (rowData, i) {
var entityId = rowData[entityIdColumn];
return $http.put('/api/' + $scope.entityType + '/' + entityId, rowData);
});
$q.all(requests).then(function (allResponses) {
//if all the requests succeeded, this will be called, and $q.all will get an
//array of all their responses.
console.log(allResponses[0].data);
}, function (error) {
//This will be called if $q.all finds any of the requests erroring.
var abc = error;
var def = 99;
});
Lorsque tous les appels $ http fonctionnent, le tableau allResponses est rempli de données.
Quand on échoue, on comprend que la deuxième fonction sera appelée et que la variable d'erreur donnera des détails.
Cependant, quelqu'un peut-il m'aider à expliquer ce qui se passe si certaines des réponses fonctionnent et que d'autres échouent?
Je crois que puisque la bibliothèque de promesses est basée sur Q
implémentation, dès que la première promesse est rejetée, le rappel de rejet est appelé avec l'erreur. Il n'attend pas que d'autres promesses soient résolues. Voir la documentation de Q
https://github.com/kriskowal/q . Pour Q.all c'est ce qui est mentionné
La fonction all renvoie une promesse pour un tableau de valeurs. Lorsque cette promesse est remplie, le tableau contient les valeurs de réalisation des promesses d'origine, dans le même ordre que ces promesses. Si l'une des promesses données est rejetée, la promesse retournée est immédiatement rejetée, sans attendre le reste du lot.
Cela fait longtemps que cette question n'a pas été postée, mais peut-être que ma réponse pourrait aider quelqu'un J'ai résolu un problème similaire en résolvant simplement toutes les promesses, mais avec un retour, je pouvais traiter plus tard et voir s'il y avait des erreurs. Voici mon exemple utilisé pour précharger certaines ressources d'image:
var loadImg = function(imageSrc) {
var deferred = $q.defer();
var img = new Image();
img.onload = function() {
deferred.resolve({
success: true,
imgUrl: imageSrc
});
};
img.onerror = img.onabort = function() {
deferred.resolve({
success: false,
imgUrl: imageSrc
});
};
img.src = imageSrc;
return deferred.promise;
}
Plus tard, je peux voir lesquelles sont erronées:
var promiseList = [];
for (var i = 0; i < myImageList.length; i++) {
promiseList[i] = loadImg(myImageList[i]);
}
$q.all(promiseList).then(
function(results) {
for (var i = 0; i < results.length; i++) {
if (!results[i].success) {
// these are errors
}
}
}
);
Edit: Uniquement supporté par Kris Kowal's Q - mais reste utile
Si vous voulez tous les traiter sans rejeter immédiatement en cas d'échec, utilisez allSettled
Voici ce que disent les docs:
Si vous voulez attendre que toutes les promesses soient remplies ou rejetées, vous pouvez utiliser allSettled.
Q.allSettled(promises)
.then(function (results) {
results.forEach(function (result) {
if (result.state === "fulfilled") {
var value = result.value;
} else {
var reason = result.reason;
}
});
});
Voici une petite réponse à cela. Dans ce violon, vous pouvez voir comment cela fonctionne, si une erreur survient dans certaines promesses.
$q.all([test1(), test2()]).then(function() {
// success
}, function() {
// error
});
J'ai trouvé un nouveau package angular qui ajoute la fonctionnalité allSettled à $ q dans angular:
Ne pourriez-vous pas simplement gérer la condition d'erreur sur vos promesses $ http avant de les transmettre à $ q? Les promesses sont chaînées, cela devrait donc marcher:
return $http.put('/api/' + $scope.entityType + '/' + entityId, rowData).then(function(r){return r;}, angular.noop);
Evidemment, vous pouvez changer le noop en n'importe quelle transformation, mais cela empêche le rejet qui empêche $q.all
d'échouer.
Dans mon cas, j’avais besoin de savoir quand la dernière promesse avait été résolue, qu’elle réussisse ou non. $ q.all n'était pas une option car s'il échoue, il tombe immédiatement en panne. J'avais besoin de cela pour m'assurer que l'utilisateur serait redirigé de toute façon, mais seulement si toutes les données sont traitées (ou non) afin qu'elles puissent être chargées sur la page suivante. Alors j'ai fini avec ça:
Je sais que c'est une façon assez boiteuse de le faire mais cela a fonctionné pour moi.