web-dev-qa-db-fra.com

Que se passe-t-il avec $ q.all () lorsque certains appels fonctionnent et que d'autres échouent?

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?

62
Alan2

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 Qhttps://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.

39
Chandermani

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
            }
        }
    }
);
38
Vexter

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;
        }
    });
});
6
Maruf

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
});

http://jsfiddle.net/wd9w0ja4/

5
user3232739

J'ai trouvé un nouveau package angular qui ajoute la fonctionnalité allSettled à $ q dans angular:

https://github.com/ohjames/angular-promise-extras

4
birdy1980

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.

1
toxaq

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:

  1. Chaque promesse/appel implémenté échoue également au rappel où la fonction "redirect" est appelée à la fois en rappel et en rappel.
  2. Dans cette fonction, le compteur est défini et augmente à chaque appel. Si cela atteint le nombre de promesses/d'appels, la redirection vers la vue suivante est effectuée.

Je sais que c'est une façon assez boiteuse de le faire mais cela a fonctionné pour moi.

0
Diomos