Skip to content

Instantly share code, notes, and snippets.

@anthonynsimon
Last active November 12, 2018 15:16
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 anthonynsimon/2852e002c2d241c7bf17bd71fd7a7bb8 to your computer and use it in GitHub Desktop.
Save anthonynsimon/2852e002c2d241c7bf17bd71fd7a7bb8 to your computer and use it in GitHub Desktop.
Deferred, naive implementation of Promises
class Deferred {
constructor(resolver) {
this._result;
this._error;
this._ready = false;
this._callbacks = [];
if (resolver) {
resolver(this.resolve.bind(this), this.reject.bind(this));
}
}
get ready() {
return this._ready;
}
resolve(result) {
this._resolve(result, undefined);
}
reject(error) {
this._resolve(undefined, error);
}
then(func) {
let next = new Deferred();
let handler = () => {
if (this._error) {
next.reject(this._error);
} else {
try {
let result = func(this._result);
if (result instanceof Deferred) {
result.then(value => next.resolve(value));
} else {
next.resolve(result);
}
} catch (error) {
next.reject(error);
}
}
};
this._enqueueHandler(handler);
return next;
}
catch(func) {
let next = new Deferred();
let handler = () => {
if (this._error) {
try {
func(this._error);
} catch (error) {
next.reject(error);
}
} else {
next.resolve(this._result);
}
};
this._enqueueHandler(handler);
return next;
}
_resolve(result, error) {
if (this.ready) {
throw new Error("deferred has already been resolved!");
}
this._result = result;
this._error = error;
this._ready = true;
this._callbacks.forEach(process.nextTick);
}
_enqueueHandler(handler) {
if (this.ready) process.nextTick(handler);
else this._callbacks.push(handler);
}
}
module.exports = Deferred;
Deferred = require("./deferred");
let one = new Deferred();
one.then(x => x + 1).then(v => console.log("[OK] chained callbacks work"));
one.then(v => console.log("[OK] independent callbacks work"));
one
.then(x => x + 5)
.then(x => {
throw new Error("hello");
})
.then(x => x + 10)
.then(v => console.log(v))
.catch(() => {
throw new Error("error handling works");
})
.catch(err =>
console.log("[OK] %s even if you throw inside a catch", err.message)
);
one
.then(x => x + 100)
.catch(v => console.error("[ERROR] should not catch non-error"))
.then(x => console.log("[OK] catch doesn't capture result if non-error %s"));
let thingy = one
.then(x => x + 5)
.then(x => {
let next = new Deferred();
setTimeout(() => {
next.resolve(x);
}, 1500);
return next;
})
.then(v => console.log("[OK] flatmap like works"))
.then(() => "voila!");
one
.then(x => x + 100)
.then(x => new Deferred((resolve, reject) => resolve(x)))
.then(v => console.log("[OK] constructor resolvers work"))
.catch(() => console.error("[ERROR] should not happend"));
one.resolve(5);
(async function() {
let res = await thingy;
console.log("[OK] result: ", res);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment