Object JavaScript – Promises for Asynchronous Operations Using jQuery

imageYou need promises as soon as you do anything that involves an asynchronous API. In Object JavaScript – Asynchronous Programming Using Promises, you learned the basics about promises.

jQuery’s implementation of promises is based around the jQuery.Deferred object. This is a chainable constructor where you can check for the existence of a promise. The jQuery Deferred object can also invoke callback queues and pass on the success of synchronous and asynchronous functions.

Deferreds were added as a part of a large rewrite of the ajax module following the Common JS/Promises A, which says a promise—what’s returned by an originator to represent a value to deliver in the future—is an object with a function called then. Consumers subscribe to fulfillment of the promise by calling then. (Promises in Windows also support a similar function called done that’s used in promise chains.)

The default state of any Deferred object is something is unresolved. Callbacks which may be added to it through .then() or .fail() are queued up and get executed later on in the process.

Let’s begin with a simple example.

jQuery Promise Example

You call promise on a jQuery selection, and you’ll get an object that you can bind event handlers too, when all the animations in the object have completed.

jQuery.ajax

So you may be wondering about whether you need to do something special for jQuery.ajax calls.

Ajax requests implement the Promise interface on the jqXHR objects returned by $.ajax(). So you receive all the properties, methods, and behavior of a Promise on the jqXHR returned value.

The following is a code example from the jQuery documentation showing how jQuery can be used to chain tasks. All of jQuery’s Ajax methods return a superset of the XMLHTTPRequest object. This jQuery XHR object, or jqXHR, returned by $.get() implements the Promise interface, giving it all the properties, methods, and behavior of a Promise

Here’s another example of how you can handle a post.

You can add as many callbacks as you want, the syntax is clear because we don’t need an extra parameter in the method.

jQuery Deferred Object

jQuery introduced a new concept in version 1.5 called Deferred which is also a derivative implementation of the CommonJS Promises/A proposal. The Deferred object exposes a then method for you to handle both the fulfillment and error states.

A Deferred is nothing more than an object that allows you to register callbacks. Calling .resolve() on a Deferred will trigger the done handlers, while calling .reject() will trigger any fail handlers.

It has two important methods:

  • resolve
  • reject

And it has three important “events” or ways to attach a callback:

  • done
  • fail
  • always

Deferred in jQuery are a chainable utility object created by calling the jQuery.Deferred() method. You can register multiple callbacks into callback queues, invoke callback queues, and relay the success or failure state of any synchronous or asynchronous function.

After creating a Deferred object, you can use any of the methods by either chaining directly from the object creation or saving the object in a variable and invoking one or more methods on that variable.

When you call resolve() on the Deferred object, any done Callbacks added by deferred.then() or deferred.done() are called. Callbacks are executed in the order they were added. Each callback is passed the args from the deferred.resolve().

So when you use deferred, you can specify when the then() and done() methods are called.

Creating Your Own Deferreds

You learned from the previous section and the previous post that $.ajax and $.when implement the deferred API internally, but you can also create your own implementations:

Here’s an example of a the HTML showing “waiting” while a long operation (wait function) occurs. wait() returns a promise that we set to pro variable. When called, wait() returns immediately with the promise that the result will be either resolved or rejected at some point in the future. pro.done() registers the result function that will be called when pro has been successfully completed.

Inside the wait() function, the deferred object resolves based on some logic inside the function (in this case, waiting two seconds). The wait function returns a promise that when the function is completed it will call of its done functions.

Instead of setTimeout, you can image an animation, Web worker, or other long running function.

jQuery Promise

The Deferred object has another important method named Promise(). This method returns an object with almost the same interface than the Deferred, but it only has methods attach callbacks and does not have the methods to resolve and reject.

Best Practice. A promise is something shared with other objects, while a deferred should be kept private within a function. Primarily, a deferred (which generally extends Promise) can resolve itself, while a promise might not be able to do so.

This is useful when you want to give to the calling API something to subscribe to, but not the ability to resolve or reject the deferred.

The literal answer is, a promise is something shared w/ other objects, while a deferred should be kept private. Primarily, a deferred (which generally extends Promise) can resolve itself, while a promise might not be able to do so.

The jQuery Promise object provides a subset of the methods of the Deferred object (then, done, fail, always, pipe. isResolved, and isRejected) to prevent users from changing the state of the Deferred.  

When you use a promise, you can still get to the deferred object. The returned Promise is linked to a Deferred object stored on the .data() for an element.

When to Integrate “Pure” Promises

Domenic Denicola wrote the article You’re Missing the Point of Promises in which he criticizes jQuery’s implementation of Promises/A. Take for example the following code:

If an error is thrown in fn1, the fail function should be called. This technique to handle errors in asynchronous functions does not work in jQuery. You can try the example out in You’re Missing the Point of Promises Gist.

Instead, you may want to use “pure” Promises/A offered in JavaScript libraries, such as Q, rsvp.js, or when.js.

You can integrate jQuery promises and convert them into a “pure” promise by converting it as soon as possible. For example:

You can learn more about Q in a later post.

References

Advertisements

One comment

  1. Pingback: Single Page App – Asynchronous Sample Using jQuery Promise to Render JSON Using Mustache | DevDays®