Let's Make a Framework: Promises Part 3
Let’s Make a Framework is an ongoing series about building a JavaScript framework from the ground up.
These articles are tagged with lmaf. The project we’re creating is called Turing. Documentation is available at 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.