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

Что происходит с $q.all(), когда некоторые вызовы работают, а другие терпят неудачу?

Что происходит с $q.all(), когда некоторые вызовы работают, а другие терпят неудачу?

У меня есть следующий код:

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

Когда все вызовы $http работают, массив allResponses заполняется данными.

Когда кто-то терпит неудачу, я понимаю, что вторая функция будет вызвана, а переменная ошибки - данные.

Однако кто-нибудь может объяснить мне, что произойдет, если некоторые из ответов будут работать, а другие потерпят неудачу?

4b9b3361

Ответ 1

Я считаю, что поскольку библиотека обещаний основана на реализации Q, как только первое обещание будет отклонено, обратный вызов reject вызывается с ошибкой. Он не ждет, пока другой promises не будет разрешен. См. Документацию Q https://github.com/kriskowal/q. Для Q.all это то, что упоминается

Вся функция возвращает обещание для массива значений. Когда это обещание выполнено, массив содержит значения выполнения оригинал promises, в том же порядке, что и promises. Если один из данный promises отклоняется, возвращенное обещание немедленно отклонен, не дожидаясь остальной части партии.

Ответ 2

Прошло некоторое время, так как этот вопрос был опубликован, но, может быть, мой ответ все равно может помочь кому-то. Я решил аналогичную проблему на моем конце, просто разрешив все promises, но с возвратом я смог обработать позже и посмотреть, есть ли какие-либо ошибки. Здесь мой пример использовался для предварительной загрузки некоторых объектов изображения:

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

Позже я вижу, какие из них ошибочны:

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

Ответ 3

Изменить: Поддерживается только в Kris Kowal Q - но все же полезный лакомый кусочек

Если вы хотите обработать все из них, не отказываясь сразу после отказа, используйте allSettled

Вот что говорят документы:

Если вы хотите дождаться выполнения всех promises или отклонено, вы можете использовать allSettled.

Q.allSettled(promises)
.then(function (results) {
    results.forEach(function (result) {
        if (result.state === "fulfilled") {
            var value = result.value;
        } else {
            var reason = result.reason;
        }
    });
});

Ответ 4

Вот небольшой ответ. В этой скрипте вы можете увидеть, как это работает, если в некоторых случаях возникает ошибка.

$q.all([test1(), test2()]).then(function() {
  // success
}, function() {
  // error
});

http://jsfiddle.net/wd9w0ja4/

Ответ 6

В моем случае мне нужно было знать, когда последнее обещание было разрешено независимо от успеха или неудачи. $q.all не был вариантом, потому что, если он не срабатывает, он сразу же опускается. Мне это нужно, чтобы убедиться, что пользователь будет перенаправлен независимо от того, но только если все данные обработаны (или нет), чтобы их можно было загрузить на следующей странице. Поэтому я закончил с этим:

  • Выполнение каждого обещания/вызова также отменяет обратный вызов, когда функция "перенаправления" вызывается как с успешным, так и с отказоустойчивым обратным вызовом.
  • В этой функции установлен счетчик, который увеличивается при каждом вызове. Если это число достигнет числа promises/звонков, выполняется перенаправление на следующий вид.

Я знаю, что это довольно хромой способ сделать это, но это сработало для меня.

Ответ 7

Не могли бы вы просто обработать условие ошибки на вашем $http promises, прежде чем передавать их в $q? promises закодированы, поэтому это должно работать:

return $http.put('/api/' + $scope.entityType + '/' + entityId, rowData).then(function(r){return r;}, angular.noop);

Очевидно, вы можете изменить noop на любое преобразование, которое вы хотите, но это предотвращает отказ, который предотвращает потерю $q.all.