Ответ 1
В javascript нет block-level scopes
только function-level scopes
:
Прочитайте эту статью о javaScript Scoping and Hoisting.
Посмотрите, как я отлаживал ваш код:
var deferred = $q.defer();
deferred.count = i;
console.log(deferred.count); // 0,1,2,3,4,5 --< all deferred objects
// some code
.success(function(data){
console.log(deferred.count); // 5,5,5,5,5,5 --< only the last deferred object
deferred.resolve(data);
})
- Когда вы пишете
var deferred= $q.defer();
внутри цикла for, он поднимает в начало функции, это означает, что javascript объявляет эту переменную в области действия внеfor loop
. - В каждом цикле последний отложенный переопределяет предыдущий, для сохранения ссылки на этот объект не существует области уровня блока.
- При вызове асинхронных обратных вызовов (успех/ошибка) они ссылаются только на последний отложенный объект, и только он разрешается, поэтому $q.all никогда не разрешается, потому что он все еще ждет других отложенных объектов.
- Вам нужно создать анонимную функцию для каждого элемента, который вы выполняете.
- Поскольку функции имеют области видимости, ссылка на отложенные объекты сохраняется в
closure scope
даже после выполнения функций. - Как прокомментировал #dfsq: нет необходимости вручную создавать новый отложенный объект, так как $http сам возвращает обещание.
Решение с angular.forEach
:
Вот демон-плункер: http://plnkr.co/edit/NGMp4ycmaCqVOmgohN53?p=preview
UploadService.uploadQuestion = function(questions){
var promises = [];
angular.forEach(questions , function(question) {
var promise = $http({
url : 'upload/question',
method: 'POST',
data : question
});
promises.push(promise);
});
return $q.all(promises);
}
Мой любимый способ - использовать Array#map
:
Вот демон-плункер: http://plnkr.co/edit/KYeTWUyxJR4mlU77svw9?p=preview
UploadService.uploadQuestion = function(questions){
var promises = questions.map(function(question) {
return $http({
url : 'upload/question',
method: 'POST',
data : question
});
});
return $q.all(promises);
}