सफलता / त्रुटि का उपयोग करना / अंत में / कोणीयजेएस में वादों के साथ पकड़ना


112

मैं $httpAngularJs में उपयोग कर रहा हूं , और मुझे यकीन नहीं है कि लौटे वादे का उपयोग कैसे करें और त्रुटियों को कैसे संभालें।

मेरे पास यह कोड है:

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

क्या यह ऐसा करने का एक अच्छा तरीका है, या एक आसान तरीका है?

जवाबों:


103

वादे उन बयानों पर अमूर्तता है जो हमें खुद को अतुल्यकालिक कोड के साथ सिंक्रनाइज़ करने की अनुमति देते हैं। वे एक समय के कार्य के निष्पादन का प्रतिनिधित्व करते हैं।

वे अपवाद हैंडलिंग भी प्रदान करते हैं, सामान्य कोड की तरह, आप एक वादे से लौट सकते हैं या आप फेंक सकते हैं।

तुल्यकालिक कोड में आप क्या चाहते हैं:

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.
}

प्रोमिसिफाइड संस्करण बहुत समान है:

$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
आप कैसे उपयोग करेंगे success(), error()और finally()किसके साथ संयुक्त होंगे catch()? या मुझे इस्तेमाल करना हैthen(successFunction, errorFunction).catch(exceotionHandling).then(cleanUp);
जोएल

3
@ आमतौर पर, आप कभी भी उपयोग नहीं करना चाहते हैं successऔर error(पसंद करें .thenऔर .catchइसके बजाय, आप ऊपर दिए गए मेरे कोड की तरह उपयोग एसी errorFunctionसे छोड़ सकते हैं (और चाहिए )। .thencatch
बेंजामिन ग्रुएनबाम

@BenjaminGruenbaum आप विस्तार से बता सकते हैं कि आप क्यों बचने का सुझाव देते हैं success/ error? इसके अलावा मेरा ग्रहण तब चलता है जब वह देखता है .catch(, इसलिए मैं ["catch"](अभी के लिए उपयोग करता हूं । मैं ग्रहण को कैसे रोक सकता हूं?
गिज़्मो

कोणीय का $ http मॉड्यूल $ q लाइब्रेरी का कार्यान्वयन .then और .catch के बजाय .suor और .error का उपयोग करता है। हालाँकि मेरे परीक्षणों में मैं .then और .catch वादों का उपयोग करते समय $ http वादे के सभी गुणों को प्राप्त कर सकता था। Zd333 का उत्तर भी देखें
स्टीव के

3
@SirBenBenji $ q के पास नहीं है .successऔर .error, $ http ने और हैंडलर के जोड़ के साथ $ q का वादा लौटाया है - हालाँकि, ये हैंडलर चेन नहीं करते हैं और आम तौर पर यदि संभव हो तो इसे टाला जाना चाहिए। सामान्य तौर पर - यदि आपके पास प्रश्न हैं, तो उन्हें नए प्रश्न के रूप में पूछना सबसे अच्छा है, न कि किसी पुरानी टिप्पणी के रूप में। successerror
बेंजामिन ग्रुएनबाम

43

उपयोग successऔर errorविधि के बारे में भूल जाओ ।

दोनों तरीकों को कोणीय 1.4 में चित्रित किया गया है। मूल रूप से, पदावनति के पीछे कारण यह है कि वे श्रृंखला-अनुकूल नहीं हैं , इसलिए बोलने के लिए।

निम्न उदाहरण के साथ, मैं प्रदर्शित करने के लिए के बारे में मैं क्या मतलब है की कोशिश करेंगे successऔर errorनहीं किया जा रहा chainable के अनुकूल है । मान लीजिए कि हम एक एपीआई कहते हैं जो एक उपयोगकर्ता ऑब्जेक्ट को एक पते के साथ लौटाता है:

उपयोगकर्ता ऑब्जेक्ट:

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

API पर कॉल करें:

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

क्या हुआ?

क्योंकि successऔर मूल वादे कोerror वापस करते हैं , यानी जिस एक के द्वारा लौटाया जाता है , वह ऑब्जेक्ट जो कॉलबैक में जाता है, वह संपूर्ण उपयोगकर्ता ऑब्जेक्ट है, जो कि पूर्ववर्ती कॉलबैक के लिए एक ही इनपुट कहना है ।$http.getthensuccess

यदि हमने दो को जंजीर में डाल दिया thenहोता, तो यह कम भ्रामक होता:

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

1
इसके अलावा लायक यह देखते हुए कि successऔर errorकर रहे हैं केवल तत्काल वापसी करने के लिए जोड़ा की $httpकॉल (प्रोटोटाइप नहीं), इसलिए यदि आप उन्हें (जैसे, आप सामान्य रूप से कॉल के बीच एक और वादा विधि कॉल return $http.get(url)एक आधार पुस्तकालय में लिपटे, लेकिन बाद में यह तय करने में एक स्पिनर टॉगल करने के लिए पुस्तकालय के साथ फोन return $http.get(url).finally(...)) तो आप अब उन सुविधा विधियों होगा।
drzaus

35

मुझे लगता है कि पिछले उत्तर सही हैं, लेकिन यहां एक और उदाहरण है (सिर्फ एक फी, सफलता () और त्रुटि) () कोणीयजीएस के मुख्य पृष्ठ के अनुसार दर्शाया गया है :

$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
अंत में मेरी जानकारी के लिए, प्रतिक्रिया वापस नहीं करता है।
डिप्लोमा

11

आप किस प्रकार की ग्रैन्युलैरिटी की तलाश कर रहे हैं? आप आमतौर पर इसके साथ प्राप्त कर सकते हैं:

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

मैंने पाया है कि कई वादों को पूरा करते समय "आखिर" और "कैच" बेहतर हैं।


1
आपके उदाहरण में, त्रुटि हैंडलर केवल $ http त्रुटियों को संभालता है।
बेंजामिन ग्रुएनबाम

1
हां, मुझे अभी भी सफलता / त्रुटि कार्यों में अपवादों को संभालने की आवश्यकता है। और फिर मुझे किसी तरह के आम हैंडलर की जरूरत है (जहां मैं चीजों को सेट कर सकता हूं loading = false)
जोएल

1
आपके पास तब () कॉल बंद करने वाले कोष्ठकों के बजाय एक ब्रेस है।
पॉल मैक्लेन

1
यह 404 प्रतिक्रिया त्रुटियों पर काम नहीं करता है, केवल .catch()मेथड पर काम करता है
elporfirio

नियंत्रकों को दी गई HTTP त्रुटियों को संभालने के लिए यह सही उत्तर है
लियोन

5

कोणीय $ http मामले में, सफलता () और त्रुटि () फ़ंक्शन के पास प्रतिक्रिया ऑब्जेक्ट अपरिवर्तित होगा, इसलिए कॉलबैक हस्ताक्षर $ http (...) की तरह होगा। सफलता (फ़ंक्शन (डेटा, स्थिति, हेडर, कॉन्फ़िगरेशन)।

तब () के लिए, आप शायद कच्ची प्रतिक्रिया वस्तु से निपटेंगे। जैसे कि AngularJS $ http API डॉक्यूमेंट में पोस्ट किया गया

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

पिछले .चैच (...) की आवश्यकता नहीं होगी जब तक कि पिछले वादे की श्रृंखला में नई त्रुटि न हो।


2
सफलता / त्रुटि विधियों को पदावनत किया जाता है।
ओवरमार

-3

मुझे यह पसंद है कि ब्रैडली ब्रेथवेट अपने ब्लॉग में सुझाव देते हैं :

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

प्रमुख बिंदु:

  • संकल्प फ़ंक्शन हमारे नियंत्रक में .then फ़ंक्शन से लिंक करता है यानी सब कुछ ठीक है, इसलिए हम अपना वादा रख सकते हैं और इसे हल कर सकते हैं।

  • अस्वीकार फ़ंक्शन लिंक को हमारे नियंत्रक में .catch फ़ंक्शन से लिंक करता है अर्थात कुछ गलत हो गया है, इसलिए हम अपना वादा नहीं रख सकते हैं और इसे अस्वीकार करने की आवश्यकता है।

यह काफी स्थिर और सुरक्षित है और यदि आपके पास वादे को अस्वीकार करने की अन्य शर्तें हैं, तो आप हमेशा सफलता के समारोह में अपने डेटा को फ़िल्टर कर सकते हैं और deferred.reject(anotherReason)अस्वीकृति के कारण के साथ कॉल कर सकते हैं ।

जैसा कि रायन वाइस ने टिप्पणियों में सुझाव दिया है , यह तब तक उपयोगी नहीं हो सकता है जब तक कि आप प्रतिक्रिया के साथ थोड़ा सा फील न करें, इसलिए बोलने के लिए।

क्योंकि successऔर error1.4 के बाद से पदावनत कर रहे हैं शायद यह नियमित रूप से वादा तरीकों का उपयोग करने के लिए बेहतर है thenऔर catchऔर उन तरीकों के भीतर प्रतिक्रिया को बदलने और उस तब्दील प्रतिक्रिया का वादा लौट आते हैं।

मैं दोनों दृष्टिकोणों के साथ एक ही उदाहरण दिखा रहा हूं और एक तीसरे इन-बीच दृष्टिकोण:

successऔर errorदृष्टिकोण ( successऔर errorHTTP प्रतिसाद का एक वादा वापस करें, इसलिए हमें $qडेटा का वादा वापस करने के लिए सहायता की आवश्यकता है ):

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

thenऔर catchदृष्टिकोण (यह फेंकने के कारण परीक्षण करने के लिए थोड़ा अधिक कठिन है):

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

एक आधा समाधान है, हालांकि (इस तरह से आप किसी भी तरह से बच सकते हैं throwऔर वैसे भी आपको $qअपने परीक्षणों में वादा व्यवहार का मजाक उड़ाने के लिए उपयोग करने की आवश्यकता होगी ):

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

किसी भी प्रकार की टिप्पणियों या सुधारों का स्वागत है।


2
वचन में लपेटने के लिए आप $ q का उपयोग क्यों करेंगे। केवल $ http.get () द्वारा लौटाए गए वादे को वापस क्यों नहीं किया जाता?
रयान वाइस

क्योंकि success()और error()एक नया वादा वापस नहीं then()करता है। साथ $qहम एक HTTP प्रतिक्रिया के वादे के बजाय डेटा के वादे के वापस जाने के लिए हमारे कारखाने हैं।
वॉचमेकर

आप प्रतिक्रिया मुझे भ्रमित कर रहे हैं इसलिए शायद मैं खुद को अच्छी तरह से नहीं समझा रहा हूं। जब तक आप प्रतिक्रिया में हेरफेर नहीं कर रहे हैं तब तक आप बस $ http रिटर्न का वादा वापस कर सकते हैं। इस उदाहरण को मैंने अभी लिखा है: jsbin.com/belagan/edit?html,js,output
रयान वाइस

1
मैं मूल्य नहीं देखता। यह मेरे लिए अनावश्यक लगता है और मैं अपनी परियोजनाओं पर कोड समीक्षाओं को अस्वीकार करता हूं जो इस दृष्टिकोण का उपयोग करते हैं लेकिन अगर आपका मूल्य इससे बाहर हो रहा है तो आपको इसका उपयोग करना चाहिए। मैंने कोणीय सर्वोत्तम अभ्यास लेखों में कुछ वादे भी देखे हैं जो एक गंध के रूप में अनावश्यक लपेटने को कहते हैं।
रयान वाइस

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.