The $q library comprises two separate APIs:

  • the deferred API, which controls a promise
  • the promise API, which contains functions for reporting on the success, failure or notification of an asynchronous operation.

You access the deferred API’s functions via a deferred object, which is created for you when you call $q.defer(). Think of this deferred object as the driver of the promise you ultimately want to use.

One of the properties of the deferred object is a promise object. It’s this promise object that you use to return values from an asynchronous call, through a set of three functions that form the promise’s API:

  • promise.then() – success
  • promise.catch() – error
  • promise.notify() – notification

The relationship between the defer object and its promise

You don’t call the promise's functions explicitly; rather, they’re called for you by the deferred object, which triggers one of these functions according to the action you wish to trigger, as follows:

  • to return a value on successful receipt of asynchronous information, you’d call defer.resolve(), which, in turn, will call its promise’s then() function.
  • if you call defer.reject(), the promise’s catch() function will be called.
  • call defer.notify(), and promise.notify() will be called.

The table below summarizes these functions, showing the deferred object’s functions and the corresponding promise functions that they call.

Deferred function Promise function
defer.resolve() promise.then()
defer.reject() promise.catch()
defer.notify() promise.notify()

The deferred object controls the promise

What you should take from this is that although it’s the promise object that you usually deal with most (for example, in REST calls made via $http or $resource), it’s actually the deferred object that you use to control the promise.

You can think of the deferred object, therefore, as the promise’s driver. Without the deferred object, the promise would just sit there waiting for a resolution or rejection that will never come.

For example:


// Create our promise’s driver
var deferred = $q.defer();

// Create a reference directly to the deferred object's
// promise property
var promise = deferred.promise;

// Wire up the promise's success and failure handlers, 
// so that the successHandler function is called on success, 
// and failureHandler is called on failure
promise
    .then(sucessHandler)
    .catch(failureHandler);

function successHandler(msg){
    console.log(msg);
}

function errorHandler(err){
   console.log(err);
}

// At this stage, the promise isn’t actually doing anything. 
// It’s just waiting for the deferred object to resolve or
// reject it.

// So let's resolve the promise...

// Do something async 
setTimer(function(){
         // Only when deferred.resolve is called will the
         // promise’s successHandler function be executed
        deferred.resolve(“Success”); 
}), 10000);

// ...and now let's reject it... 

setTimer(function(){
         // Only when deferred.reject is called will 
         // the promise’s failureHandler function be 
         // executed
         deferred.reject(“Failure”);
}), 10000);

The standard promise pattern

The simplest pattern for using a promise, with a timer used to emulate asynchronous calls.

The advantage of this approach

You may be wondering why you need to call a function on the deferred object in order for the promise’s corresponding function to be called.

The advantage that this approach provides is that it decouples your promise (i.e. the object that returns the result of your asynchronous call), from its control mechanism – the deferred object. As such, you can pass the promise around as an object that’s independent of the deferred object – return it from a function, use it in a callback function, an event, whatever you want to do with it – and still maintain control over it from your deferred object, which has the power to trigger the promise’s success or error handlers at will.

This is what happens in a call to Angular’s $http and $resource objects. Although you only handle the returned promise and you never see the deferred object that calls the promise’s success or failure handlers, the deferred object is indeed there, lurking behind the scenes deep within the AngularJS source code.

Tl;dr

The defer object contains a promise object as a property. This promise does nothing unless it’s instructed to do so by the defer object that contains it, via the defer's resolve(), reject() and notify() functions.

The Deferred Object’s API

$q.defer()

Use the $q object’s defer() function to create the defer object and access its promise.

// Create a defer object
var deferred = $q.defer();	

// We can now access the defer object's promise using 
// 'deferred.promise'
// (e.g. deferred.promise.then(function(){..}))

// It's more convenient to create a variable that references 
// 'deferred.promise' directly, though: 
var promise = deferred.promise; 

defer.resolve()

Use the defer object’s resolve() function to pass a value to the promise’s successHandler() function.

// Pass the value 'yay!' to the 
// promise's successHandler function 
deferred.resolve(‘yay!’);	

promise.then(function(data){    // successHandler
   console.log(data); //yay!
})

defer.reject()

Use the defer object’s reject() function to pass a value to the promise’s failureHandler() function.

// Pass the value 'oops!' to the 
// promise's failureHandler
deferred.reject(‘oops!);   

promise.catch(function(data){    // failureHandler
   console.log(data); //oops!
})

defer.notify()

Use the defer object’s notify function to pass a value to the promise’s notifyHandler function.


// update the user on the progress of an asynchronous task 
// that may take some time

// Pass the value 'waiting...' to 
// the promise's notifyHandler function
deferred.notify(‘waiting...’);	

promise.notify(function(data){
   console.log(data); //waiting...
});

There are no comments.

Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>