Object JavaScript – Asynchronous JavaScript Promises Using Q

687474703a2f2f6b7269736b6f77616c2e6769746875622e696f2f712f712e706e67Q is a library that implements the standard and has some extra helpers. Q works in the browser and in node.js.

Q was designed to provide a robust way to provide you ways to write asynchronous code cleanly.

If a function cannot return a value or throw an exception without blocking, it can return a promise instead. A promise is an object that represents the return value or the thrown exception that the function may eventually provide. A promise can also be used as a proxy for a remote object to overcome latency.

You can read the specifications for Q at Promises A+, which aims to clarify “the behavioral clauses of the Promises/A proposal, extending it to cover de facto behaviors and omitting parts that are underspecified or problematic.”

You use deferreds and promises in ways similar to the ways you would use them in jQuery. However, Q has some important features.

  • Exception handling. All thrown errors in the async .then callbacks will be caught and reject the promise (and will only get re-thrown if you call .end() ). jQuery does not do it this way where rejecting from then in jQuery deferreds is more complicated.
  • Several Proxy methods which will allow you to modify future values
  • Has .all and similar, which are more complicated with jQuery ( $.when.apply($, […]) ).
  • Explicitly works with Ticks in the event loop and guarantees asynchrony.

Q does not require jQuery.

Q can exchange promises with jQuery, Dojo, When.js, WinJS, and more.

This tutorial will provide a assumes you are already familiar with deferreds and promises from our earlier posts.

Getting Started with Q

You can get Q on GitHub.

You can also get Q on NuGet.

image

How You Can Use Q

The Q module can be loaded as:

  • A <script> tag (creating a Q global variable): ~2.5 KB minified and gzipped.
  • A Node.js and CommonJS module, available in npm as the q package
  • An AMD module
  • A component as microjs/q
  • Using bower as q
  • Using NuGet as Q

Q Then

When a method returns a promise that represents a value that may not yet be available. A promise is an asynchronous value. And when you make asynchronous calls in JavaScript, you have to pass a callback that is called when the method is finished.

When you use Q, you provide those callbacks in the form of methods that can be called when the promise is fulfilled or rejected.

Let’s say you have a method named delay that takes a while. And let’s further assume that delay returns a promise. And then. then() is a set of methods that can be executed once the promise is either fulfilled or rejected.

The Q documentation provides the classic usage (where s similar example is shown in Object JavaScript – Asynchronous Programming Using Promises)  where the first alert shows that the promise has been fulfilled, the second parameter when it has been rejected.


Q.delay(2000)
.then(function () {
alert('super!');
}, function () {
alert('something went wrong');
});

When you implement, the callbacks can also be null or undef.

The then method lets you chain promises together, as we have seen with jQuery promises.

Q.delay(1000)

   .then(function () {
   return 'A+ ftw!';
  }).then(function (msg) {
  alert(msg);
});

And when you return a value in the fulfilled parameter of the then() and then often want to run another function, Q provides a helper function, thenResolve. So the previous example can look like this.


Q.delay(1000)
.thenResolve('I love Q!')
.then(function (msg) {
alert(msg);
});

Serializing Work Using Promises

In my case, I want to get a my product list, get the template for the display and then filter the display based on a productCategory variable that was previously set. Along the way, each of my methods returns the values needed for the next step, and also returns a promise.

This means you can have code that chains the promises.


doTheFirstThing()
.then(doTheSecondThing)
.then(doTheThirdThing)
.then(excitement, handleError);

Parallel Tasks

In the case of loading products, you may also want to do multiple tasks and not care about the order.

Use Q.all. It converts an array of promises into a single promise that will be fulfilled when all the promises are fulfilled. Once promises are fulfilled, you get an array of all the values or rejected with the first reason a promise is rejected.

Here’s a part of code that could retrieve data and then a template, then combine them on a page.


var data = {}; // JSON data object that feeds the template
data.products = {};
var productTemplate;
Q.all([
getProducts(),
getProductTemplate()
]).then(
function (values) {
data.products = values[0];
productTemplate = values[1];
var renderedPage = Mustache.to_html(productTemplate, data);
$("#products").html(renderedPage);
}, function (err) {
$("#products").text("Load products failed: " + err.message);
});

The result of each of the function calls in Q.all is returned in an array.

Error Handling

In Q (unlike jQuery), if any of the promises chain are rejected, then the error is passed along to the first promise that can handle it. If a promise is rejected in the chain, none of the fulfill handlers will be called.

This means you can call your chain like this:


doTheFirstThing()
.then(doTheSecondThing)
.then(doTheThirdThing)
.then(null, handleError);

And the handleError method can be used to handle any error along the chain.

So if you throw an exception in any of the methods in Q, then the promise will be rejected.

Testing

José F. Romaniello points to an interesting application for this. If your  assert and test framework could handle promises, you could write something like this:


function test () {
return getSomething().should.eventually.equal(123);
}

He recommends you check out Chai as Promised.

References


2 thoughts on “Object JavaScript – Asynchronous JavaScript Promises Using Q

Comments are closed.