Angular: Returning a $q.defer().promise instead of an $http promise
Asked Answered
S

1

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.

Scrawly answered 16/3, 2015 at 17:28 Comment(3)
I'd consider this the deferred antipattern; 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)Hammon
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?Tomlin
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.Spooky
M
4

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.

Miracle answered 6/8, 2015 at 16:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.