using-promises-in-angularjs

Using Promises in AngularJS

Click here for TL;DR

As I am learning some of the new features of ES6 it has gotten me thinking about how we are currently using them is ES5. Specifically Promises. Using Promises in ES5 has been made possible by several libraries out there. Most known would be the q library by Kris Kowal. Because of my love for, and general focus on, Angular I want to talk a little about the $q Service and using Promises in AngularJS.

Using Promises in AngularJS

It is important to note that Angular’s $q Service does not actually contain Kris Kowal’s q library. However like Kris’s library it allows us to write Promises in ES5. I have seen Promises used in Angular many different ways. I wanted to touch upon how I use them and why.

What is a Promise

Many would think of a Promise as replacement for callback functions. While this is true to some extent I think this is an unfair over simplification of the power Promises really give to JavaScript developers.

A Promise acts as a sort of event listener that lets you know when something has completed, a reference to a future value. Promises can be resolved or rejects at the developers discretion .

Using the Deferred API

The Deferred API gives us access to the associated Promise instance as well as exposes API features that allows us to declare successful or unsuccessful operations. To create a new instance use $q.defer();.

Exposed to us through this API are reject(reason), resolve(reason), and notify(value).

I want to start building out our example of $q using what we know so far about using Promises in AngularJS. I think the most standard use case is an XHR Request but it is important to note that Promises do have many other use cases. Using Promises in AngularJS opens you up to many different features outside of standard XHR Requests.

In the example below we are inside one of the Services of our Angular application.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
app.service('users', users);

users.$inject = ['$q', '$http'];

function users($q, $http){

  var service = this;

  service.getUsers = function(){
    var d = $q.defer();
    $http.get('http://exampleapi.com/users')
      .success(function(response){
        //any success logic here
        return d.resolve(response.data);
      })
      .error(function(error){
        //any error logic here
        return d.reject(error);
      });
    return d.promise;
  }

  return service;

}

So lets go through what is happening above. First of all we have made an Angular Service. In that service we are making an HTTP Request to an API to get all users. Notice how we are using the .success and .error callbacks with our $http Service. It is important to note that Angular actually provides a Promise with it’s $http service but we are not using it. There is a reason for this.

Taking Control of Your Promises

I think it is more useful and flexible to take control of our Promise and resolve and reject it according to our needs, rather than letting Angular make the decision for us. Using the callbacks as shown above allows us to resolve and reject out Promise according to our strategy and plan as well as perform any additional logic we need to in the .success and .error callbacks. Returning the Promise via return d.promise mean that we have access to the Promise API whenever we use this service method. See the example controller below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
app.controller('UsersController', UsersController);

UsersController.$inject = ['users'];

function UsersController(users){
  var vm = this;
  users.getUsers()
    .then(function(data){
      //handle data
    })
    .catch(function(error){
      //handle error
    });
}

This is my preferred method for using using Promises in AngularJS. This way I can resolve and reject Promises at my discretion and pass the data through to the Promise API at my discretion as well.

The Power of Using Promises in AngularJS

There are many reasons and use cases for using Promises in AngularJS. The most common and easy to understand is their use with XHR Requests, however there are many more. In any scenario where you want to wait for an action to perform and produce data before using it in another action, a Promise will work.

Check out this Pro Tip from an earlier post to see an example of using Promises in AngularJS with a different use case.

In The End

Promises allow you to wait for future values before performing logic. In Angular we are given access to this capability via the $q Service allowing us take advantage of using Promises in AngularJS.

The $q Service gives us access to a Deferred API and a Promise API.

Using these APIs we can before operations that depend on synchronous data. See the basic example below:

1
2
3
4
5
6
7
8
9
10
11
12
function doWork(){
  var d = $q.defer();
  $http.get('http://exampleapi.com/user)
    .success(function(data){
      return d.resolve(data);
    })
  return d.promise;
}

doWork().then(function(data){
  console.log('
users data: ', data);
});

Pro Tip: npm shrink wrap

This command locks down the versions of a package’s dependencies so that you can control exactly which versions of each dependency will be used when your package is installed. The package.json file is still required if you want to use npm install.

npm shrinkwrap allows you to control with versions of each dependency you use for an npm install all the way down the dependency tree. This is useful for distributed systems as well as collaboration by many developers on a project. Read more about it here.

Leave a Reply

Your email address will not be published. Required fields are marked *