Skip to content

Instantly share code, notes, and snippets.

@baygeldin
Last active February 27, 2016 18:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save baygeldin/1c3836108bd0d41d244c to your computer and use it in GitHub Desktop.
Save baygeldin/1c3836108bd0d41d244c to your computer and use it in GitHub Desktop.
Guide to the implementation of promises.
#!usr/env/bin node
'use strict';
// Disclaimer
// The most basic promises implementation.
// I needed to do it to wrap my head around them.
// Another reason to do it was to get myself
// familiar with some code conventions, so
// sorry for ES5 :D
// Guide
// When you want to implement promises, do it
// incrementally. Step-by-step:
// 1) Implement it as state machine, without any
// methods! All it needs to do is to change it's
// state, when the promise is done.
// 2) Implement .done method. It's pretty easy, isn't it?
// It needs a handle private method in turn. All it does is
// pushing a listener (callback) to an array of listeners, or
// executes it immidiately, if promise is already done.
// 3) Implement .then method. It should return a new Promise,
// which is resolved or rejected EXACTLY when our promise is
// resolved or rejected. And it should be fulfilled with the
// result of a callback, passed to .then.
// 4) What if a callback passed to .then returns a promise?
// No problem! We can check if it's a promise when we resolve
// our promise and wait for it to be done. See resolve function.
// 5) What if a callback to .then is a bad guy and throws us
// an error? We can catch it, reject out promise and thus
// let it go down the chain.
// 6) Implement .catch if you want. It's essentially a .then
// with the first callback equals to null. Don't forget to
// catch errors or they will be swallowed! By the way, have
// you noticed that the problem of synchronous try-catch is
// gone? :)
// Implementation
function Promise(fn){
// Promise is a state machine actually
var value, handlers = [], state = 'pending';
// Just executes our state machine listeners
function handle(handler) {
if (state==='fulfilled')
handler.onFulfill(value);
else if (state==='rejected')
handler.onReject(value);
else
handlers.push(handler);
}
// If promise is fulfilled with promise -
// we should resolve it too
function resolve(result){
if (result instanceof Promise)
result.done(fulfill, reject);
else
fulfill(result);
}
// The functions for an actual resolving
// and changing state of state machine
function fulfill(result){
state = 'fulfilled';
value = result;
handlers.forEach(handle);
}
function reject(error){
state = 'rejected';
value = error;
handlers.forEach(handle);
}
// Nuffsaid
this.done = function(onFulfill, onReject){
handle({
onFulfill: onFulfill,
onReject: onReject,
});
}
// .then is easier to implement via .done
this.then = function(onFulfill, onReject){
var _this = this;
return new Promise(function(fulfill, reject){
_this.done(function(value){
// We need to check that onFulfill handler
// itself is not throwing any errors
try {
fulfill(onFulfill(value));
} catch(e){ reject(e); }
}, function(error){
if (onReject)
fulfill(onReject(error));
else
reject(error);
});
});
}
// Convinience method, just a sugar
this.catch = function(onReject){
var _this = this;
return new Promise(function(fulfill, reject){
_this.done(null, function(error){ fulfill(onReject(error)); });
});
}
// Hurray, just start to execute our promise
fn(resolve, reject);
}
// Usage
new Promise(function(fulfill, reject){
var promise = new Promise(function(fulfill, reject){
setTimeout(function(){
fulfill('200 ms passed! Not 300 ;)'); }, 200);
});
setTimeout(function(){ fulfill(promise); }, 100);
}).then(function(value){
console.log(value);
return 'I get it!';
}).then(function(value){
console.log(value);
return new Promise(function(fulfill, reject){
fulfill("I'm fulfilled by default!"); });
}).then(function(value){
console.log(value);
throw new Error('Ke-ke-ke');
}).catch(function(error){ console.log(error); });
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment