$q.all с вложенным обещанием, также созданным с помощью $q.all

Следующая функция пытается вернуть обещание, которое будет разрешено только после завершения всех асинхронных HTTP-вызовов:

$scope.saveThat = function () {
    var promises = [];

    for (var i = 0; i < array.length; i++) {
        var newPromise = $q.defer();
        promises.push(newPromise);

        // some more code...

        (function (i, newPromise) {
            $http(httpData)
                .success(function (response) {
                    newPromise.resolve('Success');
                })
                .error(function (response) {
                    newPromise.reject('Error');
                });
        })(i, newPromise);

    }
    return $q.all(promises);
};

И следующий фрагмент вызывает эту функцию.

// save this...
var promise1 = $rootScope.saveThis(result.Person);
promise1.then(function (success) {
    }, function (error) {
        saveErrorMessage += 'Error saving this: ' + error + '.';
    });

// save that...
var promise2 = $rootScope.saveThat(result.Person);
promise3.then(function (success) {
    }, function (error) {
        saveErrorMessage += 'Error saving that: ' + error + '.';
    });

// wait until all promises resolve
$q.all([promise1, promise2])
.then(
    function (success) {
        $scope.$emit(alertEvent.alert, { messages: 'Saved successfully!', alertType: alertEvent.type.success, close: true });
    }, function (error) {
        $scope.$emit(alertEvent.alert, { messages: saveErrorMessage, alertType: alertEvent.type.danger });
    });

У меня проблема в том, что второе обещание ($q.all([promise1, promise2])) разрешается, даже если обещания в promise2 еще не разрешены.


person Maria Ines Parnisari    schedule 01.11.2015    source источник
comment
Прекратите использовать отложенный антишаблон, и ваши проблемы исчезнут.   -  person Bergi    schedule 02.11.2015
comment
@Bergi, большое спасибо за это! Да, я определенно новичок в обещаниях   -  person Maria Ines Parnisari    schedule 02.11.2015


Ответы (1)


Поскольку вы не создаете массив promise, на самом деле он содержит объект $q.defer(). Вы должны использовать

promises.push(newPromise.promise);

вместо

promises.push(newPromise);

Также вам нужно избегать этих анти-шаблонов, потому что вы создаете объект $q без необходимости, поскольку у вас есть объект обещания, который вернулся из $http.get.

Код

$scope.saveThat = function() {
    var promises = [];
    for (var i = 0; i < array.length; i++) {
      // some more code...
      var promise = $http(httpData)
        .then(function(response) {
          return 'Success'; //returning data from success resolves that promise with data
        }, function(response) {
          return 'Error'; //returning data from error reject that promise with data
        });
      promises.push(promise); //creating promise array
    }
    return $q.all(promises); //apply $q.all on promise array
};
person Pankaj Parkar    schedule 01.11.2015
comment
Где вы используете переменную proimise? Где вы инициализируете newPromise? - person Maria Ines Parnisari; 02.11.2015
comment
@miparnisari, это была моя ошибка... скопируй и вставь ошибку. посмотри на мое редактирование - person Pankaj Parkar; 02.11.2015
comment
Ах, я так и думал :) спасибо за вашу помощь, я попробую то, что вы сказали, и дам вам знать. - person Maria Ines Parnisari; 02.11.2015
comment
Последний вопрос: вместо return 'Error'; можно написать return 'some custom error message;' и зафиксировать это? - person Maria Ines Parnisari; 02.11.2015
comment
@miparnisari: Вам лучше сделать throw new Error("custom message "+response), чтобы обещание было отклонено - person Bergi; 02.11.2015
comment
@miparnisari да, вы могли бы сделать это .. но Берги уже упомянул лучший способ, чем этот .. - person Pankaj Parkar; 02.11.2015