In the previous post I gave a glimpse of the Javascript Promises Pattern (JPP). Now we are going to take a more in deep look into it and implement our (simplified) version of this pattern.

First of all, let’s sow the code I we defined works: we had three operations (to make the example simpler, they all share the same code, but this is not a requisite), each of them expecting a set of arguments which are processed by an asynchronous operation. The result of this asynchronous operation will be feed to the next operation, and so on until we achieve processResults function that will handle the final result. This is a refactored version of the code exposed in the previous post:

function operation(params) {
  var promise = new Promise(this)
  async_task(params, function() {
    // ...
    promise.resolve(params);
  });
  return promise;
}

function processResults(results) {
  // ...
}

operation1 = operation;
operation2 = operation;
operation3 = operation;

operation1(params1).then(operation2).then(operation3).then(processResults);

Every operation creates a promise object that will be returned as result of the invocation to the operation. Furthermore, this promise object is used to store the future value that will result from the asynchronous call. This value is stored in the promise object using the resolve method.

operation1(params1).then(operation2).then(operation3).then(processResults);

This line is were all the magic is done: we invoke the first operation, which returns a promise object, and over this object we are invoking the then method, passing a function as its argument, which will be invoked when the promise object is resolved. Then we repeat this invocation to the then method in order to chain more callbacks, each of them being invoked by successive promise resolve invocations.

This may appear simple, but it’s kind of tricky: we pretend to receive the results of every operation as argument of the following callback. That works ok for operation1, but promises objects from operations 2 and 3 still don’t exist so there is no way to attach those promises to its correspondent callback. In other words, invoking the then method of the promise object doesn’t actually invoke operation2 and operation3 (in fact, the parameters they need are still not available). What really happens is that they are chained into the operation1 promise object.

operation1: return promise1
-> invoke then (operation2): return promise1
-> invoke then (operation3): return promise1

So how does JPP resolve this? Well, the trick can be discovered paying attention to the instantiation of the promise objects: we passed this as first argument, which in fact turns to be global object Window for promise1 and operation1 promise object for the promise2 and promise3 instantiations. That’s because resolve method invokes callbacks functions applying itself as the current scope. Maybe it’s easier to see in code:

function Promise(promise) {
    if (promise instanceof Promise) {
        return promise;
    } else {
        // this is a new promise chain
        this.callbacks = [];
    }
}

Having this idea clear, we can try to develop our own implementation for this pattern. We already have defined the constructor function, let’s go for the then and resolve methods:

Promise.prototype.then = function(callback_ok) {
    this.callbacks.push({
        ok: callback_ok
    });
    return this;
};

Promise.prototype.resolve = function() {
    var callback = this.callbacks.shift();
    if (callback && callback.ok) {
        callback.ok.apply(this, arguments);
    }
};

As we said, then just store the function to call when the resolve method is invoked. resolve then just pops the callback function to invoke, applying current promise object (this) as its scope, so when the next operation tries to create a new promise object, it gets the actual promise object instead of a new one, which turns to be the one used to define the chain of callbacks.

Well, better than to read code to understand it, is to play with it, so here you have a fiddle ready to go. It’s a litlle more complex implementation than the exposed here, because I defined a reject method, but the main idea stands.

I would love to hear feedback from you about the pattern itself or the implementation, so don’t hesitate to post comments!