deferred - AngularJS : Where to use promises? -


i saw examples of facebook login services using promises access fb graph api.

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

and services used "$scope.$digest() // manual scope evaluation" when got response

example #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 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

the questions are:

  • what difference in examples above?
  • what reasons , cases use $q service?
  • and how work?

this not going complete answer question, , others when try read documentation on $q service. took me while understand it.

let's set aside angularjs moment , consider facebook api calls. both api calls use callback mechanism notify caller when response facebook available:

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

this standard pattern handling asynchronous operations in javascript , other languages.

one big problem pattern arises when need perform sequence of asynchronous operations, each successive operation depends on result of previous operation. that's code doing:

  fb.login(function(response) {       if (response.authresponse) {           fb.api('/me', success);       } else {           fail('user cancelled login or did not authorize.');       }   }); 

first tries log in, , after verifying login successful make request graph api.

even in case, chaining 2 operations, things start messy. method askfacebookforauthentication accepts callback failure , success, happens when fb.login succeeds fb.api fails? method invokes success callback regardless of result of fb.api method.

now imagine you're trying code robust sequence of 3 or more asynchronous operations, in way handles errors @ each step , legible else or after few weeks. possible, it's easy keep nesting callbacks , lose track of errors along way.

now, let's set aside facebook api moment , consider angular promises api, implemented $q service. pattern implemented service attempt turn asynchronous programming resembling linear series of simple statements, ability 'throw' error @ step of way , handle @ end, semantically similar familiar try/catch block.

consider contrived example. have 2 functions, second function consumes result of first one:

 var firstfn = function(param) {     // param     return 'firstresult';  };   var secondfn = function(param) {     // param     return 'secondresult';  };   secondfn(firstfn());  

now imagine firstfn , secondfn both take long time complete, want process sequence asynchronously. first create new deferred object, represents chain of operations:

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

the promise property represents eventual result of chain. if log promise after creating it, you'll see empty object ({}). nothing see yet, move right along.

so far our promise represents starting point in chain. let's add our 2 operations:

 promise = promise.then(firstfn).then(secondfn); 

the then method adds step chain , returns new promise representing eventual result of extended chain. can add many steps like.

so far, have set our chain of functions, nothing has happened. things started calling deferred.resolve, specifying initial value want pass first actual step in chain:

 deferred.resolve('initial value'); 

and then...still nothing happens. ensure model changes observed, angular doesn't call first step in chain until next time $apply called:

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

so error handling? far have specified success handler @ each step in chain. then accepts error handler optional second argument. here's another, longer example of promise chain, time error handling:

 var firstfn = function(param) {     // param     if (param == 'bad value') {       return $q.reject('invalid value');     } else {       return 'firstresult';     }  };   var secondfn = function(param) {     // param     if (param == 'bad value') {       return $q.reject('invalid value');     } else {       return 'secondresult';     }  };   var thirdfn = function(param) {     // param     return 'thirdresult';  };   var errorfn = function(message) {    // handle error  };   var deferred = $q.defer();  var promise = deferred.promise.then(firstfn).then(secondfn).then(thirdfn, errorfn); 

as can see in example, each handler in chain has opportunity divert traffic next error handler instead of next success handler. in cases can have single error handler @ end of chain, can have intermediate error handlers attempt recovery.

to return examples (and questions), i'll represent 2 different ways adapt facebook's callback-oriented api angular's way of observing model changes. first example wraps api call in promise, can added scope , understood angular's templating system. second takes more brute-force approach of setting callback result directly on scope, , calling $scope.$digest() make angular aware of change external source.

the 2 examples not directly comparable, because first missing login step. however, it's desirable encapsulate interactions external apis in separate services, , deliver results controllers promises. way can keep controllers separate external concerns, , test them more mock services.


Comments

Popular posts from this blog

php - Wordpress website dashboard page or post editor content is not showing but front end data is showing properly -

javascript - Get parameter of GET request -

javascript - Twitter Bootstrap - how to add some more margin between tooltip popup and element -