Skip to main content

Implement a Custom Promise Class

You are required to implement a custom Promise.

Promise is an object that represent the eventual completion or failure of an asynchronous operation. Promise can be in 3 states:

  • Pending: The initial state, neither fulfilled nor rejected.
  • Fulfilled: The operation completed successfully.
  • Rejected: The operation failed

Example

let promise = new Promise((resolve, reject) => {
// Asynchronous operation
let success = true; // Assume the operation succeeds

if (success) {
resolve("Operation successful!");
} else {
reject("Operation failed!");
}
});

// Example of Usage
promise
.then((result) => {
console.log(result); // "Operation successful!"
})
.catch((error) => {
console.error(error); // "Operation failed!"
})
.finally(() => {
console.log("Operation completed."); // This runs no matter what
});

Solution

General structure

const STATE = {
PENDING: "PENDING",
FULFILLED: "FULFILLED",
REJECTED: "REJECTED",
};

class MyPromise {
constructor(callback) {
// Initial state of Promise is empty
this.state = STATE.PENDING;
this.value = null;
this.reason = null;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];

const resolve = (value) => {

};

const reject = (reason) => {

};

try {
callback(resolve, reject);
} catch (error) {
reject(error);
}
}

then(onSuccess, onFail) {
// ...
}

catch(onFail) {
// ...
}

finally(callback) {
// ...
}
}

resolve() and reject() methods

class MyPromise {
constructor(executor) {
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];

const resolve = (value) => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onFulfilledCallbacks.forEach((callback) => callback(this.value));
}
};

const reject = (reason) => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach((callback) => callback(this.reason));
}
};

try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
}

then() method

class MyPromise {

constructor() {
// ...
}

then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
if (this.state === "fulfilled") {
setTimeout(() => {
try {
resolve(onFulfilled(this.value));
} catch (error) {
reject(error);
}
}, 0);
} else if (this.state === "rejected") {
setTimeout(() => {
try {
reject(onRejected(this.value));
} catch (error) {
reject(error);
}
}, 0);
} else {
this.handlers.push({ onFulfilled, onRejected });
}
});
}

}

catch() and finally() methods

class MyPromise {
catch(onRejected) {
return this.then(null, onRejected);
}

finally() {

}
}

Summary

  • To implement a custom promise, you need to: Define the possible states (PENDING, FULFILLED, REJECTED).
  • Implement the resolve and reject methods to change the state and execute callbacks.
  • Implement the then, catch, and finally methods to register and handle callbacks.

References