JavaScript Custom Promise | Promise Polyfill
JavaScript Custom Promise | Promise Polyfill
👉Let’s First Write JavaScript InBuilt Promise
// This is promise callback function
let promiseFn = (resolve, reject) => {
setTimeout(() => {
resolve('I am JavaScript Inbuilt Promise');
}, 2000);
}
// Creating Promise using Promise Constructor (It takes Promise callback function as a parameter)
let p = new Promise(promiseFn);
// Promise then method (It takes success callback as a parameter)
p.then((data) => { console.log(data) });
// Promise catch method (It takes error callback as a parameter)
p.catch(console.log);
💡Understand the Promise approach
– Promise function takes one parameter and that is an executable function.
– When we call this Promise with the new keyword, it returns a promise object.
– Executable function is like a higher order function that takes two function arguments named resolve and reject.
– Promise has two public methods here, then and catch.
– Then
and Catch
method also takes callbacks which executes once the promise is resolved or rejected.
Promise Pollyfill | Custom Promise
In this Pollyfill, we are going to implement –
- A Promise Class
- Then Method
- Catch Method
Out of Scope Or which we will not implement here –
- Promise Chaining
- Finally method
- Other Promise APIs like Promise.all, any, race, etc.
Code
// These are predefined states of a promise.
const PENDING = 'PENDING';
const RESOLVED = 'RESOLVED';
const REJECTED = 'REJECTED';
function MyPromise(promiseFn) {
let state = PENDING;
let successData;
let error;
let handlerCb = [];
const resolve = function (response) {
successData = response;
state = RESOLVED;
console.log(handlerCb);
handlerCb.forEach(cb => {
queueMicrotask(() => cb(response));
});
}
const reject = function (err) {
state = REJECTED;
error = err;
if (!handlerCb) {
throw new Error(err);
}
handlerCb.forEach(cb => {
queueMicrotask(() => cb(error));
throw new Error(err);
});
}
this.then = function (cb) {
if (state === RESOLVED) {
queueMicrotask(() => cb(successData));
} else {
handlerCb.push(cb);
}
}
this.catch = function (cb) {
if (state === REJECTED) {
queueMicrotask(() => cb(error));
} else {
handlerCb.push(cb);
}
}
promiseFn(resolve, reject);
}
💻 Run the above program
let promiseFn1 = (resolve, reject) => {
setTimeout(() => {
resolve('hello I am promise polyfill');
}, 2000);
}
const p1 = new MyPromise(promiseFn1);
p1.then((data) => { console.log('then 1', data) });
// we can add multiple then on same object thats why in polyfill we have handlerCb as an array.
p1.then((data) => { console.log('then 2', data) });
👉 Let’s Understand the above Pollyfill step by step –
- The default state is Pending.
- Created a function named MyPromise which will take the promise function as argument.
- This Promise executable function requires a resolve and reject method as a parameter to execute.
- First Implement then method –
- We call then method of the promise object with a success callback as a parameter.
- Example – p.then(() => {})
- Create a then method with a callback argument.
- As we know then’s callback does not execute immediately. This runs after resolve only.
- So what can we do? we can store this callback fn in an array named handlerCb.
- One thing we can also do is that in case Promise is already resolved then we can execute this here only.
- To check Promise resolved we can check its state. (state === RESOLVED)
- Implement Resolve method
- It calls inside the promise function, Once our task is completed then we can call the resolve method with a success value.
- Create a resolve method with a parameter (success Value or response) inside our class.
- After that execute handlerCb function that we stored from then method.
- Implement Catch method
- It also takes error callback as a parameter.
- Follow the same approach as then method.
- If the state is rejected then execute the error callback immediately.
- Else store this callback in the same array named handlerCb.
- Implement Reject method
- Mark state a rejected.
- Call error callback which we stored in handlerCb variable.
- As we know Promise reject method also throws an error so we can throw an error with code – throw new Error(err).
- One extra check we can add is If someone does not implement the catch method then also throw an error.
- And last, call that promise callback function with the implemented resolve and reject method.
💡Other Notes | Keep In Mind things –
– We are executing callbacks inside the public API queueMicrotask because Promise callbacks always run in async.
– To correctly emulate the behavior we have to call it inside a microtask queue so that it is called async &
should have higher priority then normal async cbs.
– Loop over handlers callbacks and execute one one one.
– Promise then and catch method are only public methods so we add these in this object.
– resolve and reject are private methods.
JavaScript Custom Promise
const p2 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('HI I will run after 2 seconds')
}, 2000);
})
const p3 = new MyPromise((resolve, reject) => {
setTimeout(() => {
reject('HI I will rejected after 2 seconds')
}, 2000);
})
p2.then(console.log)
p3.then(console.log)
p3.catch(console.log)
const p4 = new MyPromise((resolve, reject) => {
resolve('HI I will resolved immediately seconds')
})
p4.then(console.log);
CLASS BASED STRUCTURE Of Promise Polyfill
Note Here: Just one thing to keep in mind is that we need to resolve and reject methods before promiseFn execution, so we have to create those inside the constructor function, not outside.
code
// These are predefined states of a promise.
const PENDING = 'PENDING';
const RESOLVED = 'RESOLVED';
const REJECTED = 'REJECTED';
class MyPromise1 {
state = PENDING;
successData;
error;
handlerCb;
constructor(promiseFn) {
// resolve and reject must be created here only. Cannot be created outside because we need these to call promiseFn.
const resolve = (response) => {
this.successData = response;
this.state = RESOLVED;
queueMicrotask(() => this.handlerCb && this.handlerCb(this.successData));
}
const reject = (err) => {
this.state = REJECTED;
this.error = err;
if (!this.handlerCb) {
throw new Error(err);
}
queueMicrotask(() => {
this.handlerCb && this.handlerCb(this.error);
throw new Error(this.error);
});
}
promiseFn(resolve, reject);
}
then(cb) {
if (this.state === RESOLVED) {
queueMicrotask(() => cb(this.successData));
} else {
this.handlerCb = cb;
}
}
catch(cb) {
if (this.state === REJECTED) {
queueMicrotask(() => cb(this.error));
} else {
this.handlerCb = cb;
}
}
}
💻 Run the above program
const c = new MyPromise1((resolve, reject) => {
resolve('HI I will resolved immediately seconds in Class MyPromise1')
});
c.then(console.log);
const c1 = new MyPromise1((resolve, reject) => {
setTimeout(() => {
resolve('HI I will resolved after 3 seconds in Class MyPromise1')
}, 3000);
});
c1.then(console.log);
const c2 = new MyPromise1((resolve, reject) => {
setTimeout(() => {
reject('HI I will rejected after 4 seconds in Class MyPromise1')
}, 4000);
});
c2.catch(console.log);
JavaScript Custom Promise
- Unlocking the Secrets of Cookie | Power Your Web Experience
- AI vs Human: Exploring the Boundaries of Intelligence
- Enhancing User Experience with JavaScript Throttle and Debounce
- JavaScript Custom Promise | Promise Polyfill
- JavaScript Promisify | Convert Callbacks to Promises
- JavaScript Promise and Callbacks | Everything You Must Know
- CSS Display Property – Deep dive in block | inline | inline-block
- Implementation of Queue using Linked List | JavaScript
- Insert node in Linked list | Algorithm | JavaScript
- Insertion Sort in data structure | Algorithm with Examples
- Selection Sort Algorithm & K’th Largest Element in Array
- Quick Sort Algorithm with example | Step-by-Step Guide
- Dependency Inversion Principle with Example | Solid Principles
- Object-Oriented Programming | Solid Principles with Examples
- ASCII Code of Characters | String Operations with ASCII Code
- Negative Binary Numbers & 2’s Complement | Easy explanation
- Factors of a Number | JavaScript Program | Optimized Way
- LeetCode – Game of Life Problem | Solution with JavaScript
- Fibonacci series using Recursion | While loop | ES6 Generator
- JavaScript Coding Interview Question & Answers
- LeetCode – Coin Change Problem | Dynamic Programming | JavaScript
- HackerRank Dictionaries and Maps Problem | Solution with JavaScript
- React Redux Unit Testing of Actions, Reducers, Middleware & Store
- Micro frontends with Module Federation in React Application
- React Interview Question & Answers – Mastering React
- Top React Interview Question & Answer | React Routing
- React Interview Questions and Answers | React hooks
- Higher Order Component with Functional Component | React JS
- Top React Interview Questions and Answers | Must Know
- Interview Question React | Basics for Freshers and Seniors
- Cyber Security Fundamental Questions & Answers You must know
- Application & Web Security Interview Questions & Answers
- Top Scrum Master and Agile Question & Answers 2022
- Trapping Rain Water Leetcode Problem Solution
- Array Representation of Binary Tree | Full Tree & Complete Binary Tree
- Graphs in Data Structure, Types & Traversal with BFS and DFS, Algorithms
- Traversing 2 D array with BFS & DFS Algorithm in JavaScript
- Time Complexity & Calculations | All You should know
- Backspace String Compare Leetcode Problem & Solution
- Angular Interview Questions & Answers 2021 – Part 3 – JS Mount
- Why Angular is a Preferred Choice for Developers? Top Features
- Angular Interview Questions & Answers You should know Part 2
- Top 30 JavaScript Interview Questions and Answers for 2021
- React JS Stripe Payment Gateway Integration with Node | Step by Step Guide
- Create Year Month & Date dropdown List using JavaScript & JQuery
- Create Custom QR Code Component using QR Code Styling in React JS
- How to create a common Helper class or util file in React JS
- React Build Routing with Fixed Header and Navigation | React Router Tutorial
- React Create Dashboard Layout with Side Menu, Header & Content Area
- Web Application Security Best Practices | Top Tips to Secure Angular App