AngularJS'de Promises ile başarı / hata / nihayet / catch kullanma


112

Ben kullanıyorum $httpangularjs içinde, ben iade söz nasıl kullanılacağına dair ve sap hatalarına emin değilim.

Bu koda sahibim:

$http
    .get(url)
    .success(function(data) {
        // Handle data
    })
    .error(function(data, status) {
        // Handle HTTP error
    })
    .finally(function() {
        // Execute logic independent of success/error
    })
    .catch(function(error) {
        // Catch and handle exceptions from success/error/finally functions
    });

Bu, bunu yapmanın iyi bir yolu mu yoksa daha kolay bir yolu var mı?

Yanıtlar:


103

Sözler, kendimizi eşzamanlı olmayan kodla eşzamanlı olarak ifade etmemize izin veren ifadelerin soyutlamasıdır. Tek seferlik bir görevin yerine getirilmesini temsil ederler.

Ayrıca normal kod gibi istisna işleme sağlarlar, bir sözden dönebilir veya atabilirsiniz.

Eşzamanlı kodda isteyeceğiniz şey şudur:

try{
  try{
      var res = $http.getSync("url");
      res = someProcessingOf(res);
  } catch (e) {
      console.log("Got an error!",e);
      throw e; // rethrow to not marked as handled
  }
  // do more stuff with res
} catch (e){
     // handle errors in processing or in error.
}

Söz verilen versiyon çok benzer:

$http.get("url").
then(someProcessingOf).
catch(function(e){
   console.log("got an error in initial processing",e);
   throw e; // rethrow to not marked as handled, 
            // in $q it's better to `return $q.reject(e)` here
}).then(function(res){
    // do more stuff
}).catch(function(e){
    // handle errors in processing or in error.
});

4
Nasıl kullanırsınız success(), error()ve finally()kombine catch()? Yoksa kullanmak zorunda mıyımthen(successFunction, errorFunction).catch(exceotionHandling).then(cleanUp);
Joel

3
Genellikle, hiç kullanmak istemiyorum @Joel successve error(tercih .thenve .catchbunun yerine, (ve) atlayabilirsiniz errorFunctiongelen .thenkullanım ac catchyukarıda benim kodda olduğu gibi).
Benjamin Gruenbaum

@BenjaminGruenbaum neden kaçınmayı önerdiğinizi açıklar mısınız success/ error? Ayrıca Eclipse'im gördüğünde çılgına dönüyor .catch(, bu yüzden ["catch"](şimdilik kullanıyorum. Eclipse'i nasıl evcilleştirebilirim?
Giszmo

Angular'ın $ q kitaplığının $ http modülü uygulaması .then ve .catch yerine .success ve .error kullanır. Ancak testlerimde .then ve .catch vaatlerini kullanırken $ http vaadinin tüm özelliklerine erişebildim. Ayrıca zd333'ün cevabına bakın.
Steve K

3
@SirBenBenji $ q 'ya sahip değildir .successve .error$ http , ve işleyicilerinin eklenmesiyle bir $ q vaadi döndürür - ancak, bu işleyiciler zincirlemez ve mümkünse / olduğunda genellikle kaçınılmalıdır. Genel olarak - eğer sorularınız varsa, bunları eski bir soru üzerine yorum olarak değil, yeni bir soru olarak sormanız en iyisidir. successerror
Benjamin Gruenbaum

43

Kullanmayı successve erroryöntemi unutun .

Her iki yöntem de açısal 1.4'te kullanımdan kaldırılmıştır. Temel olarak, kullanımdan kaldırmanın arkasındaki sebep, tabiri caizse zincirleme dostu olmamalarıdır .

Aşağıdaki örnekle, ne demek istediğimi successve zincirleme dostuerror olmadığımı göstermeye çalışacağım . Bir adrese sahip bir kullanıcı nesnesi döndüren bir API çağırdığımızı varsayalım:

Kullanıcı nesnesi:

{name: 'Igor', address: 'San Francisco'}

API'ye çağrı:

$http.get('/user')
    .success(function (user) {
        return user.address;   <---  
    })                            |  // you might expect that 'obj' is equal to the
    .then(function (obj) {   ------  // address of the user, but it is NOT

        console.log(obj); // -> {name: 'Igor', address: 'San Francisco'}
    });
};

Ne oldu?

Çünkü successve errordönüş orijinal söz örneğin, dönen bir $http.get, bir geri arama geçirilen nesne thenbütündür kullanıcının önceki aynı giriş demek olan bir amacı, successgeri arama.

İki tane zincirlemiş thenolsaydık, bu daha az kafa karıştırıcı olurdu:

$http.get('/user')
    .then(function (user) {
        return user.address;  
    })
    .then(function (obj) {  
        console.log(obj); // -> 'San Francisco'
    });
};

1
Ayrıca değer belirterek successve erroredilir sadece acil dönüş eklendi arasında $httponlara (gibi normalde çağrı arasında başka söz yöntemini çağırın eğer öyleyse, arama sırasında (prototip) return $http.get(url)bir taban kütüphanede sarılmış, ancak daha sonra karar bir değer değiştirici geçiş yapmak için kütüphane çağrısı ile return $http.get(url).finally(...)) artık bu kolaylık yöntemlerine sahip olmayacaksınız.
drzaus

35

Önceki cevapların doğru olduğunu düşünüyorum, ancak işte başka bir örnek (sadece bir fyi, success () ve error (), AngularJS Ana sayfasına göre kullanımdan kaldırılmıştır :

$http
    .get('http://someendpoint/maybe/returns/JSON')
    .then(function(response) {
        return response.data;
    }).catch(function(e) {
        console.log('Error: ', e);
        throw e;
    }).finally(function() {
        console.log('This finally block');
    });

3
Sonunda cevabı bilgime geri getirmiyor.
diplosaurus

11

Ne tür bir ayrıntı düzeyi arıyorsunuz? Genellikle şunlarla geçebilirsiniz:

$http.get(url).then(
  //success function
  function(results) {
    //do something w/results.data
  },
  //error function
  function(err) {
    //handle error
  }
);

Birden fazla sözü zincirlerken "sonunda" ve "yakala" nın daha iyi durumda olduğunu buldum.


1
Örneğinizde, hata işleyici yalnızca $ http hatalarını işler.
Benjamin Gruenbaum

1
Evet, yine de başarı / hata işlevlerindeki istisnaları ele almam gerekiyor. Ve sonra bir tür ortak eğiticiye ihtiyacım var (burada bazı şeyleri ayarlayabilirim loading = false)
Joel

1
Then () çağrınızı kapatan bir parantez yerine bir küme ayracı var.
Paul McClean

1
404 yanıt hatalarında Bu işe yaramazsa, sadece çalışır .catch()Yöntemi
elporfirio

Bu, denetleyicilere döndürülen http hatalarını ele almak için doğru yanıt
Leon

5

Angular $ http durumunda, success () ve error () işlevinin yanıt nesnesi sarılmamış olacaktır, bu nedenle geri arama imzası $ http (...) gibi olacaktır. Success (işlev (veri, durum, başlıklar, yapılandırma))

o zaman (), muhtemelen ham yanıt nesnesiyle ilgileneceksiniz. AngularJS $ http API belgesinde yayınlananlar gibi

$http({
        url: $scope.url,
        method: $scope.method,
        cache: $templateCache
    })
    .success(function(data, status) {
        $scope.status = status;
        $scope.data = data;
    })
    .error(function(data, status) {
        $scope.data = data || 'Request failed';
        $scope.status = status;
    });

Önceki söz zincirinde yeni bir hata atılmadığı sürece son .catch (...) 'e gerek olmayacaktır.


2
Başarı / Hata yöntemleri kullanımdan kaldırıldı.
OverMars

-3

Bradley Braithwaite'in blogunda önerdiği gibi yapıyorum :

app
    .factory('searchService', ['$q', '$http', function($q, $http) {
        var service = {};

        service.search = function search(query) {
            // We make use of Angular's $q library to create the deferred instance
            var deferred = $q.defer();

            $http
                .get('http://localhost/v1?=q' + query)
                .success(function(data) {
                    // The promise is resolved once the HTTP call is successful.
                    deferred.resolve(data);
                })
                .error(function(reason) {
                    // The promise is rejected if there is an error with the HTTP call.
                    deferred.reject(reason);
                });

            // The promise is returned to the caller
            return deferred.promise;
        };

        return service;
    }])
    .controller('SearchController', ['$scope', 'searchService', function($scope, searchService) {
        // The search service returns a promise API
        searchService
            .search($scope.query)
            .then(function(data) {
                // This is set when the promise is resolved.
                $scope.results = data;
            })
            .catch(function(reason) {
                // This is set in the event of an error.
                $scope.error = 'There has been an error: ' + reason;
            });
    }])

Anahtar noktaları:

  • Çözümleme işlevi, denetleyicimizdeki .then işlevine bağlanır, yani her şey yolunda, böylece sözümüzü tutabilir ve çözebiliriz.

  • Reddetme işlevi, denetleyicimizdeki .catch işlevine bağlanır, yani bir şeyler ters gitti, bu yüzden sözümüzü tutamayız ve onu reddetmemiz gerekir.

Oldukça kararlı ve güvenlidir ve sözü reddetmek için başka koşullarınız varsa, başarı işlevindeki verilerinizi her zaman filtreleyebilir deferred.reject(anotherReason)ve reddedilme nedeni ile arama yapabilirsiniz .

Ryan Vice'in yorumlarda önerdiği gibi, tabiri caizse yanıtla biraz uğraşmadığınız sürece bu yararlı olarak görülmeyebilir.

Çünkü successve error1.4'ten beri kullanımdan kaldırılıyor belki de normal vaat yöntemlerini kullanmak daha iyidirthen ve catchve bu yöntemlerin içinde yanıt dönüşümü ve bu dönüştürülmüş tepkinin sözünü geri dönün.

Her iki yaklaşımla ve arada üçüncü bir yaklaşımla aynı örneği gösteriyorum:

successve erroryaklaşın ( successve errorbir HTTP yanıtı vaadini verin, bu nedenle $qbir veri vaadini döndürmek için yardıma ihtiyacımız var ):

function search(query) {
  // We make use of Angular's $q library to create the deferred instance
  var deferred = $q.defer();

  $http.get('http://localhost/v1?=q' + query)
  .success(function(data,status) {
    // The promise is resolved once the HTTP call is successful.
    deferred.resolve(data);              
  })

  .error(function(reason,status) {
    // The promise is rejected if there is an error with the HTTP call.
    if(reason.error){
      deferred.reject({text:reason.error, status:status});
    }else{
      //if we don't get any answers the proxy/api will probably be down
      deferred.reject({text:'whatever', status:500});
    }
  });

  // The promise is returned to the caller
  return deferred.promise;
};

thenve catchyaklaşma (atış nedeniyle bunu test etmek biraz daha zordur):

function search(query) {

  var promise=$http.get('http://localhost/v1?=q' + query)

  .then(function (response) {
    // The promise is resolved once the HTTP call is successful.
    return response.data;
  },function(reason) {
    // The promise is rejected if there is an error with the HTTP call.
    if(reason.statusText){
      throw reason;
    }else{
      //if we don't get any answers the proxy/api will probably be down
      throw {statusText:'Call error', status:500};
    }

  });

  return promise;
}

Yine de yarım bir çözüm var (bu şekilde kaçınabilirsiniz throwve yine de muhtemelen $qtestlerinizde vaat edilen davranışla dalga geçmek için kullanmanız gerekecek ):

function search(query) {
  // We make use of Angular's $q library to create the deferred instance
  var deferred = $q.defer();

  $http.get('http://localhost/v1?=q' + query)

  .then(function (response) {
    // The promise is resolved once the HTTP call is successful.
    deferred.resolve(response.data);
  },function(reason) {
    // The promise is rejected if there is an error with the HTTP call.
    if(reason.statusText){
      deferred.reject(reason);
    }else{
      //if we don't get any answers the proxy/api will probably be down
      deferred.reject({statusText:'Call error', status:500});
    }

  });

  // The promise is returned to the caller
  return deferred.promise;
}

Her türlü yorum veya düzeltmeye açığız.


2
Sözü bir sözle tamamlamak için neden q $ kullanasın ki? Neden $ http.get () tarafından döndürülen sözü geri vermiyorsunuz?
Ryan Vice

Çünkü success()ve error()gibi yeni bir söz dönmek olmaz then()yapar. İle $qfabrikamızın bir HTTP yanıtı vaadi yerine bir veri sözü vermesini sağlıyoruz.
Saatçi

Cevabınız benim için kafa karıştırıcı, bu yüzden belki de kendimi iyi açıklamıyorum. yanıtı değiştirmiyorsanız, $ http'nin döndürdüğü sözünü geri verebilirsiniz. az önce yazdığım bu örneğe bakın: jsbin.com/belagan/edit?html,js,output
Ryan Vice

1
Değeri görmüyorum. Bana gereksiz geliyor ve bu yaklaşımı kullanan projelerimdeki kod incelemelerini reddediyorum, ancak ondan değer elde ediyorsanız kullanmalısınız. Ayrıca, açısal en iyi uygulama makalelerinde gereksiz ambalajlamayı koku olarak nitelendiren birkaç söz gördüm.
Ryan Vice

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.