8

Watching a lot of Egghead.io videos, I noticed that a common pattern is to return a custom promise and resolve it in the callbacks.

.factory('myFact', function($q, $http) {
    return {
        getData: function() {
            var deferred = $q.defer();
            $http.get('/path/to/api')
                .success(function(data) {
                    deferred.resolve(data);
                });
            return deferred.promise;
        }
    };
});

I would normally write this as:

.factory('myFact', function($http) {
    return {
        getData: function() {
            return $http.get('/path/to/api')
                .then(function(res) {
                    return res.data;
                });
        }
    };
});

Is there any advantage to returning a $q.defer() promise rather than an $http promise? The approaches look identical to me.

diplosaurus
  • 2,538
  • 5
  • 25
  • 53
  • 2
    I'd consider this the [deferred antipattern](https://github.com/petkaantonov/bluebird/wiki/Promise-anti-patterns#the-deferred-anti-pattern); however, it does take away your need to know about the `$http` object from the controller (i.e., you don't need to know the data you actually want is `response.data`, not just `data`) – Tom Mar 16 '15 at 18:00
  • 1
    The way you normally do is much better and cleaner, I see no advantage in going for the second route. `$http` already returns a promise, why create a new one? – Aurelio Mar 16 '15 at 18:10
  • You are adding a resolved promise to a resolved promise, it's just redundant. $q.defer() is more for things that dont already have a promise. – ribsies Mar 16 '15 at 19:24

1 Answers1

3

No, no advantages, it's the same, In your first code snipped you created a $q.defer() instance then you invoked its resolve() method to create a resolved promise.

That is the process you will need to know and pass throw in angularJs when working with asynchronously functions and future objects that will have different values or new data at some future moment which you will need to know when it happens because interested parties in your app may need to get access to the result of the deferred task when it completes.

Now when working with $http you don't have to do any of that because it will already return a resolved promise that you can directly invoke it's then() method unless you have a different way to do things and you need to implement a different approach.

But not all angularJs services are going to do the work for you, get a look to $resource for example, which wraps $http for use in RESTful web API scenarios. $resource will not return a resolved promise, a promise yes, you are getting one but you'll need to do the last step of resolving it (check this stack question or this and maybe this article about Amber Kaplan's own experience working with Rest).

So the way how you are doing it is good, that is how I'm doing it too when working with $http but the first snippet code is the one that we will be all searching for when we will need to do things differently with $http or forcing other services to 'work with' or 'work like' AJAX.

Community
  • 1
  • 1
Salem Ouerdani
  • 7,596
  • 3
  • 40
  • 52