Angularjs $ q.all


106

angularjs에서 $ q.all을 구현했지만 코드를 작동시킬 수 없습니다. 내 코드는 다음과 같습니다.

UploadService.uploadQuestion = function(questions){

        var promises = [];

        for(var i = 0 ; i < questions.length ; i++){

            var deffered  = $q.defer();
            var question  = questions[i]; 

            $http({

                url   : 'upload/question',
                method: 'POST',
                data  : question
            }).
            success(function(data){
                deffered.resolve(data);
            }).
            error(function(error){
                deffered.reject();
            });

            promises.push(deffered.promise);
        }

        return $q.all(promises);
    }

그리고 여기에 서비스를 호출하는 컨트롤러가 있습니다.

uploadService.uploadQuestion(questions).then(function(datas){

   //the datas can not be retrieved although the server has responded    
}, 
function(errors){ 
   //errors can not be retrieved also

})

내 서비스에서 $ q.all을 설정하는 데 문제가 있다고 생각합니다.


1
어떤 행동이 보이십니까? 그것은 당신에게 전화합니까 then(datas)? 그냥 push이것을 시도하십시오 :promises.push(deffered);
Davin Tryon

@ themyth92 내 솔루션을 시도해 보셨습니까?
Ilan Frumer 2014 년

나는 시도했고 두 방법 모두 내 경우에 작동합니다. 하지만 @Llan Frumer를 정답으로 만들 것입니다. 둘 다 정말 감사합니다.
themyth92 2014 년

1
기존 약속을 약속하는 이유는 무엇입니까? $ http는 이미 promise를 반환합니다. $ q.defer 사용은 불필요합니다.
Pete Alvin

1
그것은 것입니다 deferred하지 deffered:)
크리스토프 후씨

답변:


225

자바 스크립트에는 없습니다 block-level scopesfunction-level scopes:

자바 스크립트 범위 지정 및 호이 스팅 에 대한이 기사 읽기 .

코드를 디버깅 한 방법을 확인하세요.

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 루프 내부에 쓸 때 함수의 맨 위에 올려진다 는 것은 자바 스크립트가 .NET Framework 외부의 함수 범위에서이 변수를 선언한다는 것을 의미합니다 for loop.
  • 각 루프에서 마지막 지연 은 이전 루프를 재정의하며 해당 객체에 대한 참조를 저장할 블록 수준 범위가 없습니다.
  • 비동기 콜백 (성공 / 오류)이 호출되면 마지막 지연된 객체 만 참조 하고 해결되므로 $ q.all은 여전히 다른 지연된 객체를 기다리므로 해결되지 않습니다 .
  • 필요한 것은 반복하는 각 항목에 대해 익명 함수를 만드는 것입니다.
  • 함수에는 범위가 있기 때문에 지연된 개체에 대한 참조는 closure scope 함수가 실행 된 후에도 .
  • #dfsq가 언급했듯이 : $ http 자체가 promise를 반환하기 때문에 새로운 지연된 객체를 수동으로 구성 할 필요가 없습니다.

솔루션 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);
}

14
좋은 대답입니다. 한 가지 추가 : $ http 자체가 promise를 반환하므로 지연된 새 구성을 만들 필요가 없습니다. 따라서 더 짧을 수 있습니다. plnkr.co/edit/V3gh7Roez8WWl4NKKrqM?p=preview
dfsq

"var deferred = $ q.defer ();를 작성할 때 for 루프 내부에서 함수의 맨 위에 올립니다.". 이 부분을 이해하지 못합니다. 그 이유를 설명해 주시겠습니까?
themyth92 2014 년

나는 실제로 똑같이 할 것입니다.
dfsq 2014 년

4
map약속의 배열을 구축하는 데 사용하는 것을 좋아합니다 . 매우 간단하고 간결합니다.
Drumbeg 2015-08-10

1
선언은 게양되지만 할당은 그대로 유지됩니다. 또한 이제 'let'문을 사용한 블록 수준 범위 지정이 있습니다. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Spencer

36

$ http도 약속이므로 더 간단하게 만들 수 있습니다.

return $q.all(tasks.map(function(d){
        return $http.post('upload/tasks',d).then(someProcessCallback, onErrorCallback);
    }));

2
예, 허용되는 대답은 반 패턴의 응집 일뿐입니다.
Roamer-1888

.then()OP가 자신의 컨트롤러에서 모든 작업을 수행하기를 원 하므로 절을 생략 할 수 있다고 생각 하지만 원칙은 완전히 정확합니다.
Roamer-1888

2
물론 then 절을 생략 할 수 있습니다. 모든 HTTP 요청을 기록하려는 경우에 추가했습니다. 항상 추가하고 전역 onError 콜백을 사용하여 모든 서버 예외를 처리합니다.
Zerkotin

1
@Zerkotin은 나중에 처리 하고에 노출 하기 위해 throwa .then에서 할 수 있습니다. 그러면 문제와 글로벌을 구할 수 있습니다. $exceptionHandler
Benjamin Gruenbaum

좋은. 이것은 본질적으로 수락 된 답변의 마지막 솔루션 / 예와 동일한 접근 방식입니다.
Niko Bellic

12

문제는 추가 해야 할 약속 자체가 deffered.promise언제 deffered인지 추가하는 것 같습니다 .

promises.push(deffered);언 래핑 된 promise를 배열에 추가하지 않도록로 변경해보십시오 .

 UploadService.uploadQuestion = function(questions){

            var promises = [];

            for(var i = 0 ; i < questions.length ; i++){

                var deffered  = $q.defer();
                var question  = questions[i]; 

                $http({

                    url   : 'upload/question',
                    method: 'POST',
                    data  : question
                }).
                success(function(data){
                    deffered.resolve(data);
                }).
                error(function(error){
                    deffered.reject();
                });

                promises.push(deffered);
            }

            return $q.all(promises);
        }

이것은 deffered 객체의 배열 만 반환합니다.
Ilan Frumer 2014 년

그가 뭐라고 말했는지 모르겠지만 콘솔이 뭐라고 말했는지만
Ilan Frumer 2014 년

4
또한 문서는 $q.all지연된 객체가 아닌 약속 을 얻는다는 것을 명확하게 말합니다 . 영업 이익의 진짜 문제는 범위 지정과 함께하고 있기 때문에 그 마지막 연기 해결지고
일란 Frumer

Ilan, defer물체 를 풀어 주셔서 감사합니다 promises. 내 all()문제도 해결했습니다.
Ross Rogers

문제는 2 답변으로 해결되었으며 문제는 범위 지정 또는 가변 호이 스팅입니다.
Zerkotin 2014 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.