Angularjs $ q.all


106

$ Q.all'ı angularjs'de uyguladım, ancak kodu çalıştıramıyorum. İşte kodum:

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

Ve işte hizmetleri çağıran denetleyicim:

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

})

Hizmetimde $ q.all kurarken bir sorun olduğunu düşünüyorum.


1
Ne davranışı görüyorsun? Sizin arar mı then(datas)? Sadece şunu deneyin push:promises.push(deffered);
Davin Tryon

@ themyth92 çözümümü denedin mi?
Ilan Frumer

Denedim ve her iki yöntem de davamda çalışıyor. Ama @Llan Frumer'ı doğru cevap olarak yapacağım. İkinize de gerçekten teşekkür ederim.
themyth92

1
Neden var olan bir sözü vaat ediyorsun? $ http zaten bir söz veriyor. $ Q.defer kullanımı gereksizdir.
Pete Alvin

1
Bu deferreddeğil deffered:)
Christophe Roussy

Yanıtlar:


225

Javascript'te block-level scopessadece function-level scopes:

JavaScript Kapsam Belirleme ve Kaldırma hakkındaki bu makaleyi okuyun .

Kodunuzda nasıl hata ayıkladığımı görün:

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);
})
  • Bir var deferred= $q.defer();for döngüsünün içine yazdığınızda , bu işlevin en üstüne kaldırılır , bu, javascript'in bu değişkeni for loop.
  • Her döngüde, son ertelenen bir öncekini geçersiz kılar, bu nesneye bir referans kaydetmek için blok düzeyinde bir kapsam yoktur.
  • Eşzamansız geri aramalar (başarı / hata) çalıştırıldığında, yalnızca son ertelenen nesneye başvururlar ve yalnızca çözümlenir, bu nedenle $ q.all hiçbir zaman çözümlenmez çünkü diğer ertelenmiş nesneleri beklemeye devam eder.
  • İhtiyacınız olan şey, yinelediğiniz her öğe için anonim bir işlev oluşturmaktır.
  • İşlevlerin kapsamları olduğundan, ertelenmiş nesnelere yapılan başvuru, closure scopeişlevler çalıştırıldıktan sonra bile korunur .
  • #Dfsq'in söylediği gibi: $ http'nin kendisi bir söz verdiğinden, yeni bir ertelenmiş nesneyi manuel olarak oluşturmaya gerek yoktur.

İle çözüm angular.forEach:

İşte bir demo plunker: 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);
}

En sevdiğim yol şunu kullanmaktır Array#map:

İşte bir demo plunker: 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
İyi cevap. Bir ek: $ http'nin kendisi promise döndürdüğü için yeni ertelenmiş inşa etmeye gerek yok. Böylece daha kısa olabilir: plnkr.co/edit/V3gh7Roez8WWl4NKKrqM?p=preview
dfsq

"Var deferred = $ q.defer () yazdığınızda; for döngüsü içinde işlevin en üstüne kaldırılır." Bu kısmı anlamıyorum, arkasındaki sebebi açıklayabilir misin?
themyth92

Biliyorum, ben de aynısını yapardım.
dfsq

4
mapBir dizi vaat oluşturmak için kullanımını seviyorum . Çok basit ve özlü.
Drumbeg

1
Beyannamenin kaldırıldığı, ancak görevin olduğu yerde kaldığı unutulmamalıdır. Ayrıca, artık 'let' ifadesiyle blok düzeyinde kapsam belirleme var. Developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… sayfasına
Spencer

36

$ http de bir sözdür, daha basit hale getirebilirsiniz:

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

2
Evet, kabul edilen cevap sadece anti-modellerin bir araya toplanmasıdır.
Roamer-1888

.then()OP tüm bunları kendi kontrolöründe yapmak istediği için maddeyi dışarıda bırakabileceğinizi düşünüyorum , ancak ilke tamamen doğrudur.
Roamer-1888

2
elbette then cümlesini atlayabilirsiniz, tüm HTTP isteklerini günlüğe kaydetmek istemeniz durumunda ekledim, her zaman onları eklerim ve tüm sunucu istisnalarını işlemek için global onError geri araması kullanırım.
Zerkotin

1
Olabildiğince @Zerkotin throwbir gelen .thendaha sonra her iki kolu için ve bunu maruz $exceptionHandlersana o sıkıntı ve küresel tasarruf gereken.
Benjamin Gruenbaum

Güzel. Bu, esasen kabul edilen yanıtın son çözümü / örneğiyle aynı yaklaşımdır.
Niko Bellic

12

Sorun, eklemeniz gereken sözün deffered.promisene zaman defferedolduğunu eklemeniz gibi görünüyor :

promises.push(deffered);Sarılmamış sözü diziye eklememek için olarak değiştirmeyi deneyin .

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

Bu sadece bir dizi deffered nesne döndürür, kontrol ettim.
Ilan Frumer

Ne dediğini bilmiyorum, sadece konsolun ne dediğini bilmiyorum, çalışmadığını görebilirsiniz: plnkr.co/edit/J1ErNncNsclf3aU86D7Z?p=preview
Ilan Frumer

4
Ayrıca belgeler, $q.allertelenen nesneler değil vaatler aldığını açıkça söylüyor . OP'nin gerçek sorunu kapsam belirleme ile ilgili ve sadece son ertelenen çözüldüğü için
Ilan Frumer

Ilan, defernesneleri çözdüğün için teşekkürler ve promises. Benim all()sorunumu da çözdün.
Ross Rogers

sorun 2 cevapta çözüldü, sorun kapsam belirleme veya değişken kaldırma, ne demek isterseniz isteyin.
Zerkotin
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.