4

I'm learning Angular and I've come across two approaches to make calls that return promises. I'd like to know if one approach is better than the other and/or when you would use each.

First Technique:

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

    if (myData) {
        // call to backend was previously made and myData is already loaded 
        deferred.resolve(myData);
    } else {
        // get data from server
        $http.get(my_url_endpoint).then(function(response) {
            // cacheResult() will set myData = response.data
            deferred.resolve(cacheResult(response));
        });
    }

    return deferred.promise;
}

Second Technique:

function getSomeDataFromServer() {

    if (myData) {
        // call to backend was previously made and myData is already loaded 
        return $q.when(myData);
    } else {
        // get data from server
        return $http.get(my_url_endpoint).then(function(response) {
            // cacheResult() will set myData = response.data
            return cacheResult(response);
        });
    }
}
AlexG
  • 1,596
  • 2
  • 17
  • 26
  • Not sure if your getter function should care whether the data was already available - sounds like a controller should handle it. Another thing: in case the browser caches that http request, your first technique becomes an antipattern. – Shomz May 12 '15 at 23:27
  • The first one is the [deferred antipattern](http://stackoverflow.com/q/23803743/1048572) (and fails to forward errors). You also may want to have a look at [Caching a promise object in AngularJS service](http://stackoverflow.com/q/18744830/1048572) – Bergi May 12 '15 at 23:42
  • Closing as a duplicate of the deferred anti-pattern. I'd probably just do `var cached = null; function getSomeDataFromServer(){ return cached || (cached = $http.get(...)) }` or something like that. – Benjamin Gruenbaum May 13 '15 at 06:13

1 Answers1

4

Always prefer the second option. The first option is an anti-pattern typically seen when the developer doesn't fully understand the nature of promises. Deferred objects (var deferred = $q.defer();) are used when you have some asynchronous code that uses callbacks but needs to work with your promise based code.

Most asynchronous things you do in Angular return promises, so you would typically only use deferreds when working with a 3rd party library that relies on callbacks.

In this example, $http itself returns a promise, so creating a new deferred object is not necessary. Returning the $http promise itself is sufficient.

user2943490
  • 6,900
  • 2
  • 22
  • 38