Writing a promise library - Part 1
A simple promise implementation has four main methods.
- resolve - signal to the promise that the value it was waiting for now exists and some callback can be called with the value
- reject - signal that there was an error computing the promise’s value and the error callback should be invoked
- then - a method for registering the callback that should be invoked when the promise resolves
- catch - a method for registering the error callback that should be invoked when the promise is rejected
The following code shows a simple implementation of these four methods.
var promiseMaker = function() {
var promise = {
callback: null,
error: null
};
promise.resolve = function(data) {
this.callback(data);
};
promise.reject = function(err) {
this.error(err);
};
promise.then = function(fn) {
this.callback = fn;
};
promise.catch = function(fn) {
this.error = fn;
};
return promise;
};
This implementation doesn’t yet allow for chaining of multiple promises, but it can be used to promisify a single callback style function.
For example, the following code shows a promise version of fs.readFile
that allows the callback to be defined in the then
method.
var fs = require('fs');
var readFile = function(filename) {
var promise = promiseMaker();
fs.readFile(filename, function(err, contents) {
if (err) {
promise.reject(err);
} else {
promise.resolve(contents.toString());
}
});
return promise;
};
$ echo "hello world" > test.txt
readFile('test.txt')
.then(function(contents) {
console.log(contents);
});
## hello world
Similarly the call to then
could be replaced with a call to catch
to handle an error in reading the file.
readFile('doesnt_exist.txt')
.catch(function(err) {
console.log(err);
});
## { [Error: ENOENT, open 'doesnt_exist.txt'] errno: 34, code: 'ENOENT', path: 'doesnt_exist.txt' }
Creating chainable promises will be done in part 2…