Reputation: 5155
I was trying to implement promise from scratch.
Question:
I wasn't sure how do I implement Finally? (I'm guessing finally will execute after then's and the catch is invoked. (ONLY once))
If you feel any refactors can be made to my code, please feel free to suggest. This is my naive attempt to implement promises.
This is my implementation:
function Promisify(fn) {
let status = 0; // 0 = unfulfilled, 1 = resolved, 2 = rejected
let result;
let error;
let thenFns = [];
let catchFns = [];
let finallyFn = undefined;
// Public Methods.
this.then = function(fn) {
thenFns.push(fn);
doThen();
return this; // for chaining
};
this.catch = function(fn) {
catchFns.push(fn);
doCatch();
return this; // for chaining
};
// TODO: Implement finally
this.finally = function(fn) {
finallyFn = fn;
// dofinally(fn);
return this;
}
// Private Methods
function resolve(r) {
if (status) throw Error('can not resolve, already handled');
status = 1;
result = r;
doThen();
}
function reject(e) {
if (status) throw Error('can not reject, already handled');
status = 2;
error = e;
doCatch();
}
function doThen() {
if (status === 1) {
while(thenFns.length) {
thenFns.shift()(result);
}
}
}
function doCatch() {
if (status === 2) {
if (catchFns.length === 0) {
console.error('uncaught error')
}
while(catchFns.length) {
catchFns.shift()(error);
}
}
}
try {
fn(resolve, reject);
} catch (e) {
reject(e);
}
}
// ======== QUESTION: Caller ================
const demoFail = new Promisify((resolve, reject) => {
setTimeout(function() {
reject('Howdy! from DemoFail')
}, 1000);
});
demoFail
.then(val => console.log("DemoFail Then!!"))
.catch(console.error) //Should throw an error.
.then(val => console.log("Second then!"))
.catch(
(err) => {
throw new Error('error', err);
})
.finally(val => console.log("Executed Finally"))
Upvotes: 2
Views: 422
Reputation: 707606
Here are some things missing from your implementation:
.then()
needs to return a new promise, not the same promise..then()
handlers (if it's not a promise) becomes the resolved value of the newly returned promise returned in step #1..then()
handler is a promise, then the newly returned promise from step 1 doesn't resolve until the promise returned from the .then()
handler resolves or rejects with that value..then()
handler, you need try/catch around the call to the handler because if the handler throws, then that turns the promise returned into step #1 into a rejected promise with the throw error as the reject reason..catch()
handlers (it also returns a new promise and the return value of the handler affects the newly returned promise from step #1)..then()
or .catch()
callback fns, you also need to store the newly create promise that you returned separate for each callback because that promise will be affected by the return value or exception thrown in the callback.The spec itself that covers this is fairly simple. You can read it here. And, here's an implementation of that spec.
Your simple version looks like it probably works for one level of promise like fn().then()
, but it doesn't do proper chaining and doesn't catch exceptions in handlers and doesn't pay attention to return values in handlers which are all pretty fundamental behaviors of promises. Unfortunately, there is no super simple way to write promises that includes the fundamental behaviors. It just takes more code to support them.
Upvotes: 1