0

I'm an newbie to angular promise. I just wanted to know, how to resolve the promise synchronously. For example,

var app = angular.module("app", []);

app.service("githubService", function($http, $q) {

  var deferred = $q.defer();

  this.getAccount = function() {
    console.log(2)
    return $http.get('https://api.github.com/users/haroldrv')
      .then(function(response) {
        // promise is fulfilled
        deferred.resolve(response.data);
        return deferred.promise;
      }, function(response) {
        // the following line rejects the promise 
        deferred.reject(response);
        return deferred.promise;
      });
  };
});

app.controller("promiseController", function($scope, $q, githubService) {
  console.log(1) 
  githubService.getAccount()
    .then(
      function(result) {
        console.log(3)
        // promise was fullfilled (regardless of outcome)
        // checks for information will be peformed here
        $scope.account = result;
      },
      function(error) {
        console.log(3)
        // handle errors here
        console.log(error.statusText);
      } 
    );
    console.log(4)
});

In the above code, the values are printed in the following order 1,2,4,3. That is the service is called and getting the response synchronously. But before it resolve that http promise it received, it reaches the next line. I tried using another defer inside the response, but it doesn't work. So how to reach '4' after '3'? Here is the plunker link, http://plnkr.co/edit/AI8OJAgqFDVXb1fRYbix?p=preview

Any help on this would be greatly appreciated.

Stranger
  • 10,332
  • 18
  • 78
  • 115
  • 1
    First of all, avoid the [deferred antipattern](http://stackoverflow.com/q/23803743/1048572) (or whatever this kind of usage of deferreds is - I'm not sure this even works as intended, and if you really did intend that behaviour, there are much better and simpler solutions for caching). – Bergi Mar 31 '16 at 12:51
  • wrap `console.log(4)` into another `then` section ... – Krzysztof Safjanowski Mar 31 '16 at 12:51

2 Answers2

3

You can't, that's the nature of async calls. Any code you want to execute after a call has finished, must be placed inside the callback. The 4th log statement 'skips' the async call and is thus executed immediately.

A tip: creating a deferred object is always a code smell: 99% of the times you really don't need it. For example, you can write your service code like this and it will do exactly the same thing, but your code is much shorter:

app.service("githubService", function($http, $q) {

  this.getAccount = function() {
    console.log(2)
    return $http.get('https://api.github.com/users/haroldrv')
      .then(function(response) {
        return response.data;
      });
  };
});

For a truly excelent explanation of promises, check this blog post by Nolan Lawson.

fikkatra
  • 5,605
  • 4
  • 40
  • 66
0
  • In your plunker, If you return the $http call then you don't have to call .then() in the service it will return the promise to the controller.
  • If you want to handle response there you should use .success() and .error() callbacks there.
  • Now coming to your console.log(4) in its position it will never get executed because it is defined after githubService.getAccount() and will be executed this way immediately after it because JavaScript is asynchronously. The githubService.getAccount() will just register its callback and will move on.

I've created a plunker for you to better understand promises in javascript/angular.

Hope this helps

M. Junaid Salaat
  • 3,765
  • 1
  • 23
  • 25