Skip to content

Instantly share code, notes, and snippets.

@oeb25
Last active August 29, 2015 14:22
Show Gist options
  • Save oeb25/3791a252a0d7505f229c to your computer and use it in GitHub Desktop.
Save oeb25/3791a252a0d7505f229c to your computer and use it in GitHub Desktop.
A promise implementation in 85 LOC exluding comments
/**
* Promise Implementation in 85 LOC written in ES6
*
* This doesn't follow the official promise spec 100%, and isn't ment to.
* I only made this as a challenge, and encurage no one to use
* it for production!
*
* I wrote this without having looked at any others implementations, and may
* be slightly off!
*
* This implementation uses no `this`, and is based all around closures.
*
* I would very much like your feedback on it, anything goes!
*/
// Constants for state
const PENDING = 'pending';
const RESOLVED = 'resolved';
const REJECTED = 'rejected';
// This is the promise starting point and can be called with and without new,
// but calling it without is encuraged since .this is not used.
export default function Promize(cb) {
// We create a new "waiter", the waiter is the backbone for the promise!
var w = waiter();
// We CAN call the callback right away, since we DON'T need to let the user
// add .then and .catch beforehand!
cb(w.resolve, w.reject);
// We then return the promise methods.
return { then: w.then, 'catch': w.catch };
};
// This is the interesting stuff!
const waiter = () => {
// toCall is an array of the functions we would like to call as soon as the
// waiter completes it's previos operation.
var toCall = [];
// catchers is the same for "catchers". All the functions in here are called
// when any error occurs in the following .then's.
const catchers = [];
// Sets the current status to pending
var status = PENDING;
// The value of the promise when it has been resolved
var value;
// This is the basic `.then`. The callback can either return be a promise or
// a value.
const then = (cb) => {
// We create a waiter just as we did in the constructor.
const w = waiter();
// We then add the callback to the list of functions to call as soon as
// this operation completes!
toCall.push({
method: cb,
resolve: w.resolve
});
// We create a switch statement to handle the function depending on state
switch (status) {
case RESOLVED: {
// If the promise has already been resolved, we recall the resolve.
resolve();
break;
}
case REJECTED: {
// Same goes for the rejected.
rejected();
break;
}
};
// We again return the promise interface.
return { then: w.then, 'catch': w.catch };
};
// This is where we are told when a promise completes.
const resolve = () => {
// We set the sate of the promise to be resolved
status = RESOLVED;
if (typeof value === 'undefined')
value = arguments[0];
// We go through every callback added to the toCall.
toCall.forEach(a => {
try {
// We run the method added, and store it's result in result.
const result = a.method(value);
// We check if the result is a promise it self.
if (result && result.then)
// If it is, we return a promise, with the resolve of the next
// promise or function.
return result.then(a.resolve);
// If it's not a promise, we simple run the resolve with the result.
a.resolve(result);
// If any errors occur they will be caught here.
} catch (e) {
// If no "catchers" is added, we simply throw the error. If there is a
// catch at an erlier stage in the promise, it will make it's way back
// there!
if (catchers.length < 1)
throw e;
// We set the state to rejected
state = REJECTED;
// We do the same as with the results. In this way we can have multiple
// catchers to the same promise chain!
catchers.forEach(c => c(e));
}
});
// We clear the toCall array to prevent running the same `.then` twice.
toCall = [];
};
// reject simply throws an error with the supplyied message!
const reject = msg => {
// We set the state to rejected
state = REJECTED;
throw new Error(msg);
};
// _chatch addes the "catcher" to the list of "catchers", in the same way
// .then does! It then returns the same .then and catch instead of
// creating a new.
// It's named "_catch" because "catch" is a reserved word.
const _catch = (e) => {
onError.push(e);
// We again return the promise interface!
return { then, 'catch': _catch };
};
// Returns the functions.
return { then, resolve, reject, 'catch': _catch };
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment