How to write a Promise/A+ compatible library


I decided to write Adehun after the series of promise posts. Adehun means ‘Promise’ in Yoruba, the language of my West African tribe. After a lot of rewrites, I can say Alhamdulillaah,  Adehun passes all the compliance tests of the promise/tests repo.

And here is how I did it.

1. Promise States & Validity

An object mapping the various states to integers and an isValidStates function to verify that only valid states are accepted.

2. Utils

A couple of helper functions including runAsync (to run functions asynchronously), isObject, isFunction and isPromise helper functions.

3. The Transition function – Gatekeeper for State Transition 

Gatekeeper function; ensures that state transitions occur when all required conditions are met.

If conditions are met, this function updates the promise’s state and value. It then triggers the process function for further processing.

The process function carries out the right action based on the transition (e.g. pending to fulfilled) and is explained later.


function transition (state, value) {
  if (this.state === state ||
    this.state !== validStates.PENDING ||
    !isValidState(state)) {
      return;
    }

  this.value = value;
  this.state = state;
  this.process();
}

4. The Then function

The then function takes in two optional arguments (onFulfill and onReject handlers) and must return a new promise. Two major requirements:

1. The base promise (the one on which then is called) needs to create a new promise using the passed in handlers; the base also stores an internal reference to this created promise so it can be invoked once the base promise is fulfilled/rejected.

2. If the base promise  is settled (i.e. fulfilled or rejected), then the appropriate handler should be called immediately. Adehun.js handles this scenario by calling process in the then function.

function then (onFulfilled, onRejected) {
 var queuedPromise = new Adehun();
 if (Utils.isFunction(onFulfilled)) {
   queuedPromise.handlers.fulfill =
                        onFulfilled;
 }

 if (Utils.isFunction(onRejected)) {
   queuedPromise.handlers.reject =
                        onRejected;
 }

 this.queue.push(queuedPromise);
 this.process();

 return queuedPromise;
}

5. The Process function – Processing Transitions

This is called after state transitions or when the then function is invoked. Thus it needs to check for pending promises since it might have been invoked from the then function.

Process runs the Promise Resolution procedure on all internally stored promises (i.e. those that were attached to the base promise through the then function) and enforces the following Promise/A+ requirements:

1. Invoking the handlers asynchronously using the Utils.runAsync helper (a thin wrapper around setTimeout (setImmediate will also work)).

2. Creating fallback handlers for the onSuccess and onReject handlers if they are missing.

3. Selecting the correct handler function based on the promise state e.g. fulfilled or rejected.

4. Applying the handler to the base promise’s value. The value of this operation is passed to the Resolve function to complete the promise processing cycle.

5. If an error occurs, then the attached promise is immediately rejected.


function process () {
 var that = this,
     fulfillFallBack = function (value) {
       return value;
     },
     rejectFallBack = function (reason) {
       throw reason;
     }; 

 if (this.state === validStates.PENDING) {
   return;
 }

 Utils.runAsync(function () {
   while (that.queue.length) {
     var queuedP = that.queue.shift(),
     handler = null,
     value;

     if(that.state===validStates.FULFILLED){
       handler = queuedP.handlers.fulfill ||
                 fulfillFallBack;
     }
     if(that.state===validStates.REJECTED){
       handler = queuedP.handlers.reject ||
                 rejectFallBack;
     }

     try {
       value = handler(that.value);
     } catch (e) {
       queuedP.reject(e);
       continue;
     }

   Resolve(queuedP, value);
  }
 });
}

6. The Resolve function – Resolving Promises

This is probably the most important part of the promise implementation since it handles promise resolution. It accepts two parameters – the promise and its resolution value.

While there are lots of checks for various possible resolution values; the interesting resolution scenarios are two – those involving a promise being passed in and a thenable  (an object with a then value).

1. Passing in a Promise value

If the resolution value is another promise, then the promise must adopt this resolution value’s state. Since this resolution value can be pending or settled, the easiest way to do this is to attach a new then handler to the resolution value and handle the original promise therein. Whenever it settles, then the original promise will be resolved or rejected.

2. Passing in a thenable value

The catch here is that the thenable value’s then function must be invoked  only once (a good use for the once wrapper from functional programming). Likewise, if the retrieval of the then function throws an Exception, the promise is to be rejected immediately.

Like before, the then function is invoked with functions that ultimately resolve or reject the promise but the difference here is the called flag which is set on the first call and turns subsequent calls are no ops.

function Resolve(promise, x) {
  if (promise === x) {
    var msg = "Promise can't be value";
    promise.reject(new TypeError(msg));
  }
  else if (Utils.isPromise(x)) {
    if (x.state === validStates.PENDING){
      x.then(function (val) {
        Resolve(promise, val);
      }, function (reason) {
        promise.reject(reason);
      });
    } else {
      promise.transition(x.state, x.value);
    }
  }
  else if (Utils.isObject(x) ||
           Utils.isFunction(x)) {
    var called = false,
        thenHandler;

    try {
      thenHandler = x.then;

      if (Utils.isFunction(thenHandler)){
        thenHandler.call(x,
          function (y) {
            if (!called) {
              Resolve(promise, y);
              called = true;
            }
          }, function (r) {
            if (!called) {
              promise.reject(r);
              called = true;
            }
       });
     } else {
       promise.fulfill(x);
       called = true;
     }
   } catch (e) {
     if (!called) {
       promise.reject(e);
       called = true;
     }
   }
 }
 else {
   promise.fulfill(x);
 }
}

7.  The Promise Constructor

And this is the one that puts it all together. The fulfill and reject functions are syntactic sugar that pass no-op functions to resolve and reject.


var Adehun = function (fn) {
 var that = this;

 this.value = null;
 this.state = validStates.PENDING;
 this.queue = [];
 this.handlers = {
   fulfill : null,
   reject : null
 };

 if (fn) {
   fn(function (value) {
     Resolve(that, value);
   }, function (reason) {
     that.reject(reason);
   });
 }
};

I hope this helped shed more light into the way promises work.

AdehunJS on Github.

Liked this post? Here are a couple more exciting posts!

1. The Differences between jQuery Deferreds and the Promises/A+ spec

2. Programming Language Type Systems II

3. Three Important JavaScript Concepts

3 Ways to start using promises


Continuing from the previous post; lets dive into ways of using promises. First, some helper functions:

var log = console.log.bind(console);

function delay(fn, time){
   setTimeout(function() {
       fn(time);
   }, time);
}

1. Pseudo-Observers

This involves attaching several handlers to a single promise; all attached handlers are invoked once the promise resolves. I call this the ‘pseudo-observer’ pattern because each ‘observer’ gets invoked once (remember promises never leave their resolution state). This explains why promises can’t be used to implement pubsub.

p = new Promise(function(resolve,reject){
    delay(resolve, 2000);
});

function foo(){
  p.then(function(val) {
     log("foo called after " + val + "ms");
  });
}

function bar(){
  p.then(function(val) {
     log("bar called after " + val + "ms");
  });
}

foo();
bar();

// -- After 2 seconds --
//log: foo called after 2000ms
//log: bar called after 2000ms

2. Parallelizing Asynchronous operations

Here’s a trivial example of the pending operations pattern which uses a counter to monitor multiple parallel async operations:

var pendingOps = 0;

function allDone (){
   pendingOps--;
   log("Pending calls: ", pendingOps);

   if(pendingOps === 0){
      log("All done");
   }
}

pendingOps++;
delay(allDone, 4000);

pendingOps++;
delay(allDone, 2000);

// -- After 2 seconds --
//log: Pending calls: 1

// -- After 4 seconds --
//log: Pending calls: 0
//log: All done

Although this approach works, it requires counter changes for every new async operation. It is also risky – a wrong counter change and you get a difficult bug. Alternative approach? Promises of course!

The Promise.all ‘static’ method takes an array of promises and only resolves when all of its promises are resolved. The then function is called with an array of values corresponding to the resolution states of the input promises and in their original order.

p = new Promise(function(resolve,reject){
    delay(resolve, 4000);
});

p2 = new Promise(function(resolve,reject){
    delay(resolve, 2000);
});

Promise.all([p,p2]).then(function(values){
    log(values);
});

// -- After 4 seconds ---
//log: [4000,2000]

An iterable must be passed to the Promise.all function otherwise it’ll cause an error.

//fails because input is not iterable
Promise.all(p, p2).then(function(values){
   log(values);
}).catch(function(error){
   log(error);
});

//log: TypeError: invalid_argument

3. Ordering Asynchronous operations

Web developers sometimes need to make an async request using the results of an earlier async request. For example, retrieving the id of a user and then using that to get more information.  This is implemented by using a callback inside a callback, something like the timeout example below:

var val = null;
setTimeout(function() {
   val = "val set in first call";
   log(val);

   setTimeout(function() {
       if(val){
           log("Inside second call");
       }
   }, 2000);
}, 2000);

//log: val set in first call
//log: Inside second call

The example above shows two nested callbacks, the first one returns and sets a value which is then used in the second callback – this is typical of what happens in a lot of AJAX requests. However this approach is brittle, requires careful checks to avoid bugs and can be broken if async operations complete out of order. Just as you expected, promises can help…

p1 = new Promise(function(resolve,reject){
    delay(resolve, 4000);
});

p1.then(function (val) {
  log("P1 done after "+ val + " ms");
  p2 = new Promise(function(rslv,rjct){
      delay(rslv, 2000);
  });

  return p2;
}).then(function (val) {
  log("P2 done after "+ val + "ms");
});

//-- 4 second wait --
//log: P1 done after 4000ms
// -- 2 second wait --
//log: P2 done after 2000ms

The second then call waits until the new Promise is fulfilled (or rejected) before it is called. If a non-promise value is passed in, it will execute immediately, however since a promise was passed to it, it ‘waited’ for the promise to fulfill before executing.

And that’s about it! Insha Allaah, the next post should be about the compatibility issues between jQuery Defereds and the Promise/A+ specification.

Introduction to JavaScript Promises


A promise is a value that might not exist because the action needed to produce that value has not been carried out. Thus, after the expected action has run, the promise will have a value indicating the success or failure of the action.

Promises were first introduced by Friedman and Wise in their 1976 paper – The Impact of Applicative Programming on Multiprocessing. A lot of languages have implemented the concepts and some examples include the C# Task, Python and Java’s Futures as well as the JavaScript Promise.

JavaScript promises simplify asynchronous programming by avoiding the bane of convoluted callbacks. They can be used for async and synchronous tasks although usage is mostly tied to AJAX requests.

Callback issues

The most popular way of asynchronous programming in JavaScript, using callbacks, has a couple of drawbacks.

1. Error handling

Callbacks have to accept error handler parameters since there is no way to guarantee the success or failure of an asynchronous operation.

Synchronous error handling constructs like the try/catch can’t be used since async errors might not occur in the body of the try/catch block.

Do you now know why jQuery’s $.ajax has a onerror function?

2. Returning values

Callbacks cannot return values – they only accept parameters. The continuation passing style provides a workaround but can easily result in a tangle of callbacks.

If an async operation might fail then error-handling callbacks have to be created at each layer. This leads to error-handling chains that can stretch forever (yeah I am exaggerating but you do get the point).

Promises help to avoid this since they return values that allow execution in a seemingly synchronous way and prevent polluting function signatures to capture success/errors.

The JavaScript Promise

Think of a promise as a state machine – there are specified valid states and transitions.

  • Pending – not yet resolved
  • Succeeded / Fulfilled – pending operation succeeded
  • Failed / Rejected – pending operation failed

A promise starts out in the pending state and can end up in only one of the fulfilled or rejected states. Thus it is either ‘fulfilled’ with some value or fails due to a reason. Success and failure are mutually exclusive events – only one can occur. Whichever of these two happens, the associated callback gets invoked notifying consumers of the operation’s status.

Resolution to success/failed states occurs once – once resolved, a promise never leaves the success/failed state. This rule ensures the immediate invocation of callbacks attached to resolved promises; this prevents deadlocks from happening – imagine a callback ‘waiting’ for an already resolved promise to be resolved.

Here’s how to declare a promise:

var p = new Promise(onresolve, onreject);
var q = new Promise(function(rslv, rjct){..});

And here is a really simple example of using promises

var p = new Promise(
  function(onresolve, onreject){
    setTimeout(function () {
        onresolve("done after 2 seconds");
    }, 2000);
});

p.then(function(value) {
    console.log(value);
});
//done after 2 seconds

The MDN specification for promises highlights a couple of useful methods including

  • Promise.all which allows resolving a list of promises in parallel
  • Promise.reject which allows creating rejected promises with a particular value
  • Promise.resolve which allows creating resolved promises with a particular value
  • Promise.prototype.catch (Instance method) which is syntactic sugar allow you to catch promise rejects.

This was a shallow dive into promises, the next post insha Allaah will cover promise usage patterns.