Bir angularjs sözünü iade etmeden önce çözebilir misin?


125

Söz veren bir işlev yazmaya çalışıyorum. Ancak istenen bilgilerin hemen elde edilebildiği zamanlar vardır. Tüketicinin bir karar vermesine gerek kalmaması için bunu bir sözle sarmak istiyorum.

function getSomething(id) {
    if (Cache[id]) {
        var deferred = $q.defer();
        deferred.resolve(Cache[id]); // <-- Can I do this?
        return deferred.promise;
    } else {
        return $http.get('/someUrl', {id:id});
    }
}

Ve bunu şu şekilde kullanın:

somethingService.getSomething(5).then(function(thing) {
    alert(thing);
});

Sorun, geri aramanın önceden çözülmüş söz için yürütülmemesidir. Bu yapılacak meşru bir şey mi? Bu durumu halletmenin daha iyi bir yolu var mı?


10
İlk durumda dönüşü yazmanın daha basit bir yolu return $q.when(Cache[id]). Her neyse, bu işe yaramalı ve her seferinde yeni vaatler oluşturduğunuz için her seferinde geri aramayı aramalıdır.
musically_ut


1
Rezil. Hayatımın bir saatini kaybetti. Bunu bir birim testinde deniyordum ve söz, test tamamlandıktan sonra yerine getirildi ve görmedim. Testimle ilgili sorun, kodla değil.
Craig Celeste 13

Test sırasında işlerin hemen çözülmesini sağlamak için $ kapsam. $ Apply () aradığınızdan emin olun.
dtabuenc

Bence httpbackend.flush bunu açıklıyor ama $ q olmayabilir. Bu testte kapsam kullanmıyorum. Hizmeti doğrudan test ediyorum, ancak yine de çalıştırdım, teşekkürler.
Craig Celeste

Yanıtlar:


174

Kısa cevap: Evet, bir AngularJS sözünü iade etmeden önce çözebilirsiniz ve beklediğiniz gibi davranacaktır.

Gönderen JB NIZET en Plunkr ama aslen isteneni kapsamında çalışmalarına refactored (hizmetine yani bir işlev çağrısı) ve aslında sitede.

Hizmetin içinde ...

function getSomething(id) {
    // There will always be a promise so always declare it.
    var deferred = $q.defer();
    if (Cache[id]) {
        // Resolve the deferred $q object before returning the promise
        deferred.resolve(Cache[id]); 
        return deferred.promise;
    } 
    // else- not in cache 
    $http.get('/someUrl', {id:id}).success(function(data){
        // Store your data or what ever.... 
        // Then resolve
        deferred.resolve(data);               
    }).error(function(data, status, headers, config) {
        deferred.reject("Error: request returned status " + status); 
    });
    return deferred.promise;

}

Kontrolörün içinde ...

somethingService.getSomething(5).then(    
    function(thing) {     // On success
        alert(thing);
    },
    function(message) {   // On failure
        alert(message);
    }
);

Umarım birine yardımcı olur. Diğer cevapları çok net bulamadım.


2
Ne kadar mutlu olduğumu kelimelerle tarif edemem, bana çok zaman kazandırdığını h.coates!
rilar

Http GET'in başarısız olması durumunda, iade edilen söz bu şekilde reddedilmez.
lex82

5
Yani bu gönderi için tl; dr: Evet, bir sözü geri vermeden önce çözebilirsiniz ve amaçlandığı gibi kısa devre yapacaktır.
ray

1
Bu cevap, Kris Kowal'ın Angular'ın vaatlerinin dayandığı Q'su için de geçerlidir.
Keith

Cevabınıza bir hata işleme örneği ekledim, umarım sorun olmaz.
Simon East

98

Angular 1.x'te önceden çözülmüş bir söz nasıl basitçe iade edilir

Çözülmüş söz:

return $q.when( someValue );    // angular 1.2+
return $q.resolve( someValue ); // angular 1.4+, alias to `when` to match ES6

Reddedilen söz:

return $q.reject( someValue );

1
O fabrikaya gerek yok, bu yardımcı fonksiyonlar zaten mevcut:{resolved: $q.when, rejected: $q.reject}
Bergi

Hey Bergi, değerli katkılarınız için teşekkür ederim. Cevabımı buna göre düzenledim.
Andrey Mikhaylov - lolmaus

2
Bu cevabın seçilmesi gerektiğini düşünüyorum.
Morteza Tourani

@mortezaT Seçilmiş olsaydı, bana altın bir rozet vermezdi. ;)
Andrey Mikhaylov - lolmaus

6

Verileri gerçekten dizide veya nesnede önbelleğe almak istersem bunu genellikle nasıl yaparım

app.factory('DataService', function($q, $http) {
  var cache = {};
  var service= {       
    getData: function(id, callback) {
      var deffered = $q.defer();
      if (cache[id]) {         
        deffered.resolve(cache[id])
      } else {            
        $http.get('data.json').then(function(res) {
          cache[id] = res.data;              
          deffered.resolve(cache[id])
        })
      }
      return deffered.promise.then(callback)
    }
  }

  return service

})

DEMO


0

Önbellek öğesini başlatmayı unuttunuz

function getSomething(id) {
    if (Cache[id]) {
        var deferred = $q.defer();
        deferred.resolve(Cache[id]); // <-- Can I do this?
        return deferred.promise;
    } else {
        Cache[id] = $http.get('/someUrl', {id:id});
        return Cache[id];
    }
}

Afedersiniz. Bu doğru. Sorudaki açıklık için kodu basitleştirmeye çalışıyordum. Öyle olsa bile, önceden çözülmüş söze girerse, geri aramayı çağırıyor gibi görünmüyor.
Craig Celeste 13

2
Bir sözü bir sözle çözerseniz, içsel vaadin düzleşeceğini sanmıyorum. Bu Cache, amaçlanan nesneler yerine sözlerle doldurulur ve bir nesnenin Önbellekte olduğu ve olmadığı durumlarda aynı olmayacağı durumlar için dönüş türü. Bu daha doğru, sanırım:$http.get('/someUrl', {id: id}).then(function (response) { Cache[id] = response.data; return Cache[id]; });
musically_ut

0

Kaynağımdan veri almak için bir fabrika kullanmayı severim.

.factory("SweetFactory", [ "$http", "$q", "$resource", function( $http, $q, $resource ) {
    return $resource("/sweet/app", {}, {
        "put": {
            method: "PUT",
            isArray: false
        },"get": {
            method: "GET",
            isArray: false
        }
    });
}]);

Öyleyse modelimi burada bu şekilde hizmette gösterin

 .service("SweetService",  [ "$q", "$filter",  "$log", "SweetFactory",
    function ($q, $filter, $log, SweetFactory) {

        var service = this;

        //Object that may be exposed by a controller if desired update using get and put methods provided
        service.stuff={
            //all kinds of stuff
        };

        service.listOfStuff = [
            {value:"", text:"Please Select"},
            {value:"stuff", text:"stuff"}];

        service.getStuff = function () {

            var deferred = $q.defer();

          var promise = SweetFactory.get().$promise.then(
                function (response) {
                    if (response.response.result.code !== "COOL_BABY") {
                        deferred.reject(response);
                    } else {
                        deferred.resolve(response);
                        console.log("stuff is got", service.alerts);
                        return deferred.promise;
                    }

                }
            ).catch(
                function (error) {
                    deferred.reject(error);
                    console.log("failed to get stuff");
                }
            );

            promise.then(function(response){
                //...do some stuff to sett your stuff maybe fancy it up
                service.stuff.formattedStuff = $filter('stuffFormatter')(service.stuff);

            });


            return service.stuff;
        };


        service.putStuff = function () {
            console.log("putting stuff eh", service.stuff);

            //maybe do stuff to your stuff

            AlertsFactory.put(service.stuff).$promise.then(function (response) {
                console.log("yep yep", response.response.code);
                service.getStuff();
            }).catch(function (errorData) {
                alert("Failed to update stuff" + errorData.response.code);
            });

        };

    }]);

Daha sonra denetleyicilerim, onu dahil edebilir ve ortaya çıkarabilir veya yalnızca enjekte edilen Hizmete atıfta bulunarak bağlamında doğru olanı yapabilir. Ne olursa olsun.

İyi çalışıyor gibi görünüyor. Ama ben açısal için biraz yeniyim. * hata işleme çoğunlukla netlik sağlamak için dışarıda bırakılır


Kişisel getStuffyöntem kullanıyor ertelenmiş antipattern
Bergi
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.