DailyJS

Let's Make a Framework: Promises Part 3

Alex R. Young

Subscribe

@dailyjs

Facebook

Google+

tutorials frameworks lmaf documentation promises

Let's Make a Framework: Promises Part 3

Posted by Alex R. Young on .
Featured

tutorials frameworks lmaf documentation promises

Let's Make a Framework: Promises Part 3

Posted by Alex R. Young on .
*Let's Make a Framework* is an ongoing series about building a JavaScript framework from the ground up. These articles are tagged with [lmaf](http://dailyjs.com/tags.html#lmaf). The project we're creating is called [Turing](http://github.com/alexyoung/turing.js). Documentation is available at [turingjs.com](http://turingjs.com/).

Over the last two weeks I've been looking at how web frameworks
implement promises, and I've built a little Promise class
along the way.

Building on the Promise Class

To build on last week's example we first need to make it sit alongside
the rest of the framework code. I've created
turing.promise.js, and test/promise_test.js,
then added code comments for Turing's annotated source code.

Here's what the annotated source looks like now:

/*!
 * Turing Promise
 * Copyright (C) 2010-2011 Alex R. Young
 * MIT Licensed
 */

/**
 * The Turing Promise module.
 */
(function() {

  /**
   * The Promise class.
   */
  function Promise() {
    var self = this;
    this.pending = [];

    /**
     * Resolves a promise.
     *
     * @param {Object} A value
     */
    this.resolve = function(result) {
      self.complete('resolve', result);
    },

This is what part of the unit test looks like:

'test then': function() {
  function delay(ms) {
    var p = new turing.Promise();
    setTimeout(p.resolve, ms);
    return p;
  }

  function timeout(duration, limit) {
    var p = new turing.Promise();
    setTimeout(p.resolve, duration);
    setTimeout(p.reject, limit);
    return p;
  }

  delay(1000).then(function() {
    assert.ok('Delay completed');
  });

Framework Integration

One of the reasons I was interested in using promises was to make
animation code more accessible. The following example should be
possible:

turing().delay(1000).then(function() {
  // A second has passed!
});

This could be tested by looking at the current time:

'test chain': function() {
  var start = (new Date()).valueOf();

  // Don't match on exactly 1000 because setTimeout isn't accurate
  turing().delay(1010).then(function() {
    assert.ok((new Date()).valueOf() - start >= 1000);
  });
}

Implementation

A few months ago we added "middleware" to Turing which allows features
to be injected based on the parameters passed to turing().
Satisfying the previous test requires no parameters. In future, the
Promise module should be integrated with the animation
module and supporting chain hooks can be added there:

var chain = {};

turing.init(function() {
  if (arguments.length === 0)
    return chain;
});

chain.delay = function(ms) {
  var p = new turing.Promise();
  setTimeout(p.resolve, ms);
  return p;
};

Now turing().delay(1000).then(callback); is entirely
possible!

Conclusion

I've updated Turing's repository with all of this, in commit
d64f0cf
.