AngularJS: वादों का उपयोग कहाँ करें?


141

मैंने फेसबुक लॉगिन सेवाओं के कुछ उदाहरण देखे जो वादों का उपयोग कर रहे थे एफबी ग्राफ एपीआई तक पहुंचने के का उपयोग ।

उदाहरण # 1 :

this.api = function(item) {
  var deferred = $q.defer();
  if (item) {
    facebook.FB.api('/' + item, function (result) {
      $rootScope.$apply(function () {
        if (angular.isUndefined(result.error)) {
          deferred.resolve(result);
        } else {
          deferred.reject(result.error);
        }
      });
    });
  }
  return deferred.promise;
}

और सेवाओं है कि इस्तेमाल किया "$scope.$digest() // Manual scope evaluation" प्रतिक्रिया मिलने पर

उदाहरण # 2 :

angular.module('HomePageModule', []).factory('facebookConnect', function() {
    return new function() {
        this.askFacebookForAuthentication = function(fail, success) {
            FB.login(function(response) {
                if (response.authResponse) {
                    FB.api('/me', success);
                } else {
                    fail('User cancelled login or did not fully authorize.');
                }
            });
        }
    }
});

function ConnectCtrl(facebookConnect, $scope, $resource) {

    $scope.user = {}
    $scope.error = null;

    $scope.registerWithFacebook = function() {
        facebookConnect.askFacebookForAuthentication(
        function(reason) { // fail
            $scope.error = reason;
        }, function(user) { // success
            $scope.user = user
            $scope.$digest() // Manual scope evaluation
        });
    }
}

JSFiddle

प्रश्न हैं:

  • अंतर क्या है?उपरोक्त उदाहरणों में है?
  • $ Q का उपयोग करने के क्या कारण और मामले हैं सेवा ?
  • और यह कैसे काम करता है ?

9
लगता है कि आपको यह पढ़ना चाहिए कि वादे क्या हैं, और वे सामान्य रूप से क्यों उपयोग किए जाते हैं ... वे कोणीय के लिए अनन्य नहीं हैं और उपलब्ध सामग्री के बहुत सारे हैं
charlietfl

1
@charlietfl, अच्छी बात है, लेकिन मुझे एक जटिल उत्तर की उम्मीद थी जो दोनों को कवर करेगा: क्यों वे सामान्य रूप से उपयोग किए जाते हैं और इसे कोणीय में कैसे उपयोग किया जाए। आपके सुझाव के लिए धन्यवाद
माकसिम

जवाबों:


401

यह आपके प्रश्न का पूर्ण उत्तर देने वाला नहीं है, लेकिन उम्मीद है कि इससे आपको और अन्य लोगों को उस समय मदद मिलेगी जब आप दस्तावेज़ को पढ़ने की कोशिश करेंगे $q सेवा । इसे समझने में मुझे थोड़ा समय लगा।

आइए एक पल के लिए AngularJS को सेट करें और बस Facebook API कॉल पर विचार करें। जब Facebook से प्रतिक्रिया मिलती है, तो कॉल करने के लिए दोनों API कॉल एक कॉलबैक तंत्र का उपयोग करते हैं :

  facebook.FB.api('/' + item, function (result) {
    if (result.error) {
      // handle error
    } else {
      // handle success
    }
  });
  // program continues while request is pending
  ...

यह जावास्क्रिप्ट और अन्य भाषाओं में अतुल्यकालिक संचालन से निपटने के लिए एक मानक पैटर्न है।

इस पैटर्न के साथ एक बड़ी समस्या तब उत्पन्न होती है जब आपको अतुल्यकालिक संचालन के अनुक्रम को करने की आवश्यकता होती है, जहां प्रत्येक क्रमिक ऑपरेशन पिछले ऑपरेशन के परिणाम पर निर्भर करता है। यह कोड क्या कर रहा है:

  FB.login(function(response) {
      if (response.authResponse) {
          FB.api('/me', success);
      } else {
          fail('User cancelled login or did not fully authorize.');
      }
  });

पहले यह लॉग इन करने की कोशिश करता है, और उसके बाद ही यह सत्यापित करने के बाद कि लॉगिन सफल था, यह ग्राफ एपीआई के लिए अनुरोध करता है।

यहां तक ​​कि इस मामले में, जो केवल दो ऑपरेशनों का एक साथ पीछा कर रहा है, चीजें गड़बड़ होने लगती हैं। विधि askFacebookForAuthenticationविफलता और सफलता के लिए एक कॉलबैक स्वीकार करती है, लेकिन क्या होता है जब FB.loginसफल होता है लेकिन FB.apiअसफल होता है? यह विधि विधि successके परिणाम की परवाह किए बिना हमेशा कॉलबैक को आमंत्रित करती है FB.api

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

अब, चलिए एक पल के लिए Facebook API सेट करते हैं और $qसेवा द्वारा कार्यान्वित की गई Angular Promises API पर विचार करते हैं । इस सेवा द्वारा लागू किया गया पैटर्न अतुल्यकालिक प्रोग्रामिंग को सरल कथनों की एक लीनियर श्रृंखला से मिलता-जुलता कुछ करने की कोशिश है, जिस तरह से किसी भी कदम पर एक त्रुटि को 'फेंक' करने और अंत में इसे संभालने की क्षमता, शब्दार्थ के समान परिचित try/catchब्लॉक।

इस आकस्मिक उदाहरण पर विचार करें। मान लें कि हमारे दो कार्य हैं, जहां दूसरा फ़ंक्शन पहले वाले परिणाम का उपभोग करता है:

 var firstFn = function(param) {
    // do something with param
    return 'firstResult';
 };

 var secondFn = function(param) {
    // do something with param
    return 'secondResult';
 };

 secondFn(firstFn()); 

अब कल्पना करें कि FirstFn और secondFn दोनों को पूरा होने में लंबा समय लगता है, इसलिए हम इस क्रम को अतुल्यकालिक रूप से संसाधित करना चाहते हैं। पहले हम एक नई deferredवस्तु बनाते हैं , जो संचालन की श्रृंखला का प्रतिनिधित्व करती है:

 var deferred = $q.defer();
 var promise = deferred.promise;

promiseसंपत्ति श्रृंखला का अंतिम परिणाम प्रतिनिधित्व करता है। यदि आप इसे बनाने के तुरंत बाद एक वादा करते हैं, तो आप देखेंगे कि यह सिर्फ एक खाली वस्तु है ({} ) है। अभी तक देखने के लिए कुछ भी नहीं, सही साथ ले जाएँ।

अब तक हमारा वादा केवल श्रृंखला में शुरुआती बिंदु का प्रतिनिधित्व करता है। अब अपने दो ऑपरेशन जोड़ते हैं:

 promise = promise.then(firstFn).then(secondFn);

thenविधि श्रृंखला के लिए एक कदम कहते हैं और फिर एक नई वादा विस्तारित श्रृंखला का अंतिम परिणाम का प्रतिनिधित्व करने देता है। आप जितने चाहें उतने चरण जोड़ सकते हैं।

अब तक, हमने अपने कार्यों की श्रृंखला स्थापित की है, लेकिन वास्तव में कुछ भी नहीं हुआ है। आपको कॉलिंग द्वारा शुरू की गई चीजें मिलती हैं deferred.resolve, जो उस प्रारंभिक मूल्य को निर्दिष्ट करता है जिसे आप श्रृंखला के पहले वास्तविक चरण में पास करना चाहते हैं:

 deferred.resolve('initial value');

और फिर ... फिर भी कुछ नहीं होता। यह सुनिश्चित करने के लिए कि मॉडल परिवर्तन ठीक से देखे गए हैं, जब तक अगली बार नहीं $applyबुलाया जाता है , तब तक कोणीय वास्तव में श्रृंखला में पहला कदम नहीं कहता है:

 deferred.resolve('initial value');
 $rootScope.$apply();

 // or     
 $rootScope.$apply(function() {
    deferred.resolve('initial value');
 });

तो त्रुटि से निपटने के बारे में क्या? अब तक हमने श्रृंखला में प्रत्येक चरण में केवल एक सफल हैंडलर निर्दिष्ट किया है। thenएक वैकल्पिक द्वितीय तर्क के रूप में एक त्रुटि हैंडलर को भी स्वीकार करता है। इस बार एक और वादा श्रृंखला का उदाहरण है, इस बार त्रुटि से निपटने के लिए:

 var firstFn = function(param) {
    // do something with param
    if (param == 'bad value') {
      return $q.reject('invalid value');
    } else {
      return 'firstResult';
    }
 };

 var secondFn = function(param) {
    // do something with param
    if (param == 'bad value') {
      return $q.reject('invalid value');
    } else {
      return 'secondResult';
    }
 };

 var thirdFn = function(param) {
    // do something with param
    return 'thirdResult';
 };

 var errorFn = function(message) {
   // handle error
 };

 var deferred = $q.defer();
 var promise = deferred.promise.then(firstFn).then(secondFn).then(thirdFn, errorFn);

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

अपने उदाहरणों (और आपके प्रश्नों) पर जल्दी लौटने के लिए, मैं सिर्फ इतना कहूंगा कि वे दो अलग-अलग तरीकों का प्रतिनिधित्व करते हैं जो फेसबुक के कॉलबैक-उन्मुख एपीआई को एंगुलर के मॉडल परिवर्तनों को देखने के तरीके के अनुकूल बनाते हैं। पहला उदाहरण एक वादे में एपीआई कॉल को लपेटता है, जिसे एक दायरे में जोड़ा जा सकता है और इसे एंगुलर के टेम्प्लेटिंग सिस्टम द्वारा समझा जाता है। दूसरा सीधे कॉलबैक परिणाम को स्कोप पर सेट करने का अधिक जानवर-बल दृष्टिकोण लेता है, और फिर $scope.$digest()बाह्य स्रोत से परिवर्तन के बारे में कोणीय को अवगत कराने के लिए बुला रहा है।

दो उदाहरण सीधे तुलनीय नहीं हैं, क्योंकि पहला लॉगिन चरण याद कर रहा है। हालांकि, यह आम तौर पर अलग-अलग सेवाओं में इस तरह बाहरी एपीआई के साथ बातचीत को एनकैप्सुलेट करने के लिए वांछनीय है, और परिणामों को वादे के रूप में नियंत्रकों को वितरित करता है। इस तरह आप अपने नियंत्रकों को बाहरी चिंताओं से अलग रख सकते हैं, और नकली सेवाओं के साथ उन्हें अधिक आसानी से परख सकते हैं।


5
मुझे लगता है कि यह बहुत अच्छा जवाब है! मेरे लिए मुख्य बात, सामान्य मामले का वर्णन करना था जब वादा वास्तव में वास्तविक होता है। ईमानदारी से मैं एक और वास्तविक उदाहरण की उम्मीद कर रहा था (जैसे फेसबुक के साथ), लेकिन यह भी मुझे लगता है कि काम करता है। बहुत धन्यवाद!
मिकसिम

2
कई thenतरीकों का उपयोग करने का एक विकल्प है $q.all। उस पर एक त्वरित ट्यूटोरियल यहां पाया जा सकता है
बोगदान

2
$q.allयदि आपको कई स्वतंत्र अतुल्यकालिक कार्यों को पूरा करने के लिए प्रतीक्षा करने की आवश्यकता है तो उचित है । यदि प्रत्येक ऑपरेशन पिछले ऑपरेशन के परिणाम पर निर्भर करता है, तो यह चेनिंग को प्रतिस्थापित नहीं करता है।
कर्लगोल्ड

1
इसके बाद की रूपरेखा को यहाँ स्पष्ट रूप से समझाया गया है। मुझे इसकी पूर्ण क्षमता को समझने और उपयोग करने में मदद की। साभार
तुषार जोशी

1
शानदार जवाब @karlgold! मेरा एक सवाल है। यदि, अंतिम कोड स्निपेट में, आप return 'firstResult'भाग को बदल देते हैं return $q.resolve('firstResult'), तो क्या अंतर होगा?
टेक्नोफाइल

9

मुझे एक जटिल उत्तर की उम्मीद थी जो दोनों को कवर करेगा: क्यों वे सामान्य रूप से उपयोग किए जाते हैं और इसे कोणीय में कैसे उपयोग किया जाए

यह एमवीपी (न्यूनतम व्यवहार्य वादे) के लिए कोणीय वादे हैं : http://plnkr.co/edit/QBAB0usWXc96TnxqKhuA?p=preview

स्रोत:

(लिंक पर क्लिक करने के लिए आलसी उन लोगों के लिए)

index.html

  <head>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.js"></script>
    <script src="app.js"></script>
  </head>

  <body ng-app="myModule" ng-controller="HelloCtrl">
    <h1>Messages</h1>
    <ul>
      <li ng-repeat="message in messages">{{ message }}</li>
    </ul>
  </body>

</html>

app.js

angular.module('myModule', [])

  .factory('HelloWorld', function($q, $timeout) {

    var getMessages = function() {
      var deferred = $q.defer();

      $timeout(function() {
        deferred.resolve(['Hello', 'world']);
      }, 2000);

      return deferred.promise;
    };

    return {
      getMessages: getMessages
    };

  })

  .controller('HelloCtrl', function($scope, HelloWorld) {

    $scope.messages = HelloWorld.getMessages();

  });

(मुझे पता है कि यह आपके विशिष्ट फेसबुक उदाहरण को हल नहीं करता है लेकिन मुझे निम्नलिखित स्निपेट उपयोगी लगते हैं)

वाया: http://markdalgleish.com/2013/06/use-promises-in-angularjs-views/


28 फरवरी 2014 को अपडेट करें: 1.2.0 के अनुसार, वादों को अब टेम्पलेट्स द्वारा हल नहीं किया जाता है। http://www.benlesh.com/2013/02/angularjs-creating-service-with-http.html

(प्लंकर उदाहरण 1.1.5 का उपयोग करता है।)


afaik हम इसलिए प्यार करते हैं क्योंकि हम आलसी हैं
mkb

इसने मुझे $ q, आस्थगित और जंजीर समझने में मदद की। तब फ़ंक्शन को कॉल किया, इसलिए धन्यवाद।
एलिओपी

1

आस्थगित एक अतुल्यकालिक ऑपरेशन के परिणाम का प्रतिनिधित्व करता है। यह एक इंटरफ़ेस को उजागर करता है जिसका उपयोग राज्य को संकेत देने के लिए किया जा सकता है और उस ऑपरेशन के परिणाम का प्रतिनिधित्व करता है। यह संबंधित वादा उदाहरण प्राप्त करने का एक तरीका भी प्रदान करता है।

एक वादा यह संबंधित आस्थगित के साथ बातचीत करने के लिए एक इंटरफ़ेस प्रदान करता है, और इसलिए, इच्छुक पार्टियों को राज्य तक पहुंचने और आस्थगित ऑपरेशन के परिणाम के लिए अनुमति देता है।

एक आस्थगित बनाते समय, यह स्थिति लंबित है और इसका कोई परिणाम नहीं है। जब हम आस्थगित () या अस्वीकार () को हल करते हैं, तो यह बदल जाता है यह हल या अस्वीकार करने के लिए स्थिति है। फिर भी, हम आस्थगित बनाने के तुरंत बाद संबद्ध वादा प्राप्त कर सकते हैं और यहां तक ​​कि भविष्य के परिणाम के साथ बातचीत भी कर सकते हैं। स्थगित किए गए या हल किए जाने के बाद ही वे इंटरैक्शन होंगे।


1

एक नियंत्रक के भीतर वादा का उपयोग करें और सुनिश्चित करें कि डेटा उपलब्ध है या नहीं

 var app = angular.module("app",[]);
      
      app.controller("test",function($scope,$q){
        var deferred = $q.defer();
        deferred.resolve("Hi");
        deferred.promise.then(function(data){
        console.log(data);    
        })
      });
      angular.bootstrap(document,["app"]);
<!DOCTYPE html>
<html>

  <head>
    <script data-require="angular.js@*" data-semver="1.3.0-beta.5" src="https://code.angularjs.org/1.3.0-beta.5/angular.js"></script>
  </head>

  <body>
    <h1>Hello Angular</h1>
    <div ng-controller="test">
    </div>
  </body>

</html>

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