Kitson P. Kelly avatar

A recovering 7 foot tall cactus

dojo/promise

It seems that my dojo/request article got a few views, so I figured I would take a moment to talk about dojo/promise, another major enhancement in the core of the Dojo Toolkit in 1.8. Mark Wubben rewrote the promise API while keeping it compatible with the “modern” Dojo promise API.

Just a reminder, the “modern” promise API arrived in Dojo 1.5, where “callback chaining” and the promise was introduced. Prior to that you had to use addCallback and addErrback when dealing with a Deferred object. As of 1.5, the API changed so you could do something like this:

var d = new Deferred();

d.then(function (results) {
  // Do something when the Deferred resolves
});

None of that changes for 1.8, but the underpinnings have totally changed and there is a more robust API for managing promises and futures. In 1.8, the new abstract class of dojo/promise/Promise is introduced. This provides the core API of Promises in Dojo and is what dojo/Deferred now implements. Plus there are a couple of new syntactically named methods:

var d = new Deferred();

d.then(function (value) {
  // Do something when the promise completes
}, function (err) {
  // Do something when the promise errors
}, function (update) {
  // Do something when the promise provides progress
});

d.fail(function (err) {
  // Do something only when the promise fails
});

d.both(function (value) {
  // Do the same thing in case of success or failure
});

Dealing with multiple promises (like for example, making several requests to several services) and then doing something when one or all of them were resolved was dealt with dojo/DeferredList. While that is still there (and still works), dojo/promise has introduced two new syntactically named modules dojo/promise/all and dojo/promise/first, which will roll up a bunch of promises and return you a new promise that could work something like this:

require(["dojo/Deferred", "dojo/promise/all", "dojo/promise/first"]),
function(Deferred, all, first){
  var d1 = new Deferred();
  var d2 = new Deferred();
 
  all([d1, d2]).then(function(results){
    // Do something when both Deferreds are resolved
  });
 
  first([d1, d2]).then(function(results){
    // Do something when either of the Deferreds are resolved
  });
});

The last significant “new thing” in my opinion is that there is the dojo/promise/tracer. What this does is essentially allow you to centrally manage the events of Promises. What you do is load the module and then on any of your Promises/Deferred, turn on trace by calling the .trace() (or .traceRejected()):

require(["dojo/promise/tracer", "dojo/Deferred"], function(tracer)){
  // Create a deferred
  var deferred = new Deferred();
  // Enable tracing
  deferred.promise.trace();
 
  // Setup event handlers
  tracer.on("resolved", function(args){
    // Handle a resolved event
  });
  tracer.on("rejected", function(args){
    // Handle a rejected event
  });
  tracer.on("progress", function(args){
    // Handle a progress event
  });
});

So like dojo/request, I think there are some really “cool” things coming in 1.8 in the “core” of Dojo.