Custom promise implementation(Promise polyfill)

Custom promise implementation(Promise polyfill)

Hi Everyone,

My name is sai and i work in Front-end stack.

Let's understand how to create your own version of promise.

Let's dive into the methods and fields present inside a promise class

This is the code sandbox link to full implementation of custom promise.

https://codesandbox.io/s/jovial-benji-qggtjn?file=/src/index.js

First Let's understand the flow of a promise

const promiseCheck = new MyPromise((resolve,reject)=>{
   setTimeout(()=>res('Hello'),2000);
});
promiseCheck.then(response=>console.log(response)).catch(err=>err);
promiseCheck.then(response=>console.log(response + 'world');        

  1. When creating a new MyPromise, you provide it with a callback.
  2. The callback is immediately invoked when the MyPromise is created.
  3. This callback receives two arguments: 'resolve' and 'reject'.
  4. Within these callback, you perform asynchronous operations and use 'resolve' or 'reject' accordingly.
  5. Since JavaScript is synchronous, it doesn't wait for async tasks in these callbacks to finish.
  6. Even if you perform synchronous operations, 'resolve' and 'reject' use 'queueMicroTask' to execute after the call stack is empty.
  7. The next step involves collecting all 'then' and 'catch' callbacks for these promises.
  8. The '.then()' function takes two arguments: 'successCallback' and 'failedCallback'.
  9. '.then()' always returns a new promise and is used for chaining.
  10. so the sync process of promise is done.
  11. Then once the resolve or reject is called from your callback.
  12. Once 'resolve' or 'reject' is called from your callback, it updates the state and checks if the returned value is a promise or a normal value.
  13. If it's a promise, it waits for it to resolve.
  14. If not, it calls the success or failed callbacks based on the response.
  15. Therefore, each '.then()' in the chaining creates a new promise.

State

The first field is state which defines what state a promise is in.

const STATE = {
    FULFILLED: "fulfilled",
    REJECTED: "rejected",
    PENDING: "pending",
}

class MyPromise {
  state = STATE.PENDING; // init state
}        

Private Fields

#value; // value to store the result of the promise
#successCallbacks = []; // this is used to store the then functions 
#failedCallbacks = []; // this is used to store all the catch blocks        
# indicate private members, check this link for more details

Constructor

constructor(cb){
  cb(this.#onResolve, this.#onReject);
}

// cb is the callback FN which will be called in promise constructor
// Example
// new MyPromise((resolve, reject) => resolve('Done')).then();
// (resolve, reject) => resolve('Done') this part is the cb        

#onResolve

#onResolve = (value) => {
    queueMicrotask(() => {
        if (value instanceof MyPromise || value instanceof Promise){
            value.then(this.#onResolve, this.#onReject);
            return;
        }
        this.#value = value;
        this.state = STATE.FULFILLED;
        this.#runCallbacks();
    })
}        

  1. #onResolve will get called once you resolve a promise.
  2. Similarly #onReject will get called once you call reject in a promise.
  3. queueMicrotask (window function) , the cb you passed will get executed once the call stack is empty. This will help to maintain promises exectue asynchronously.
  4. You can return another promise from a then block or onResolve also.
  5. so if the returned value is a promise then you have wait till it is executed.
  6. if not a promise then store the value and update state and run all the then and catch callbacks
  7. Same checks you need to add for #onReject.

Most important .then, .catch, .finally and chaining

Let's see .then

then = (resolveCb, rejectCb) => {
    return new MyPromise((resolve, reject) => {
        this.#successCallbacks.push((result) => {
            if (resolveCb === undefined) {
                resolve(result);
                return;
            }
            try {
                resolve(resolveCb(result));
            } catch (err) {
                reject(err);
            }
        });

        this.#failedCallbacks.push((reject) => {
            if (rejectCb === undefined) {
                reject(result);
                return;
            }
            try {
                resolve(rejectCb(result));
            } catch (err) {
                reject(err);
            }
        });
        this.#runCallbacks();
    })
}        

  1. .then() takes two args, first one is resolveCb, second one is rejectCb
  2. Every .then() returns a new promise(used for chaining)
  3. we will store the callbacks which were passed to .then(cb) inside array.
  4. The reason for array is because same promise can have different .then()
  5. In those callback array we are resolving or rejecting new promise based on the result.
  6. if any of the callback function is not provided then we will directly resolve/reject promise.

Catch and finally are very simple they are dependent on .then
catch = (rejectCb) => {
    return this.then(undefined, rejectCb);
}

finally = (cb) => {
    return this.then((value) => {
        cb(value);
        return value;
    }, () => {
        cb(value);
        return value;
    })
}        

Finally on callbacks are being run

#runCallbacks = () => {
    if (this.state === STATE.PENDING) {
        return;
    }

    if (this.state === STATE.FULFILLED) {
        this.#successCallbacks.forEach(cb => {
            cb(this.#value);
        })
    }

    if (this.state === STATE.REJECTED) {
        this.#failedCallbacks.forEach(cb => {
            cb(this.#value);
        })
    }
}        

Call all the callback array based on the status.


And i referred the below links to write this article

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

https://www.youtube.com/watch?v=1l4wHWQCCIc&t=4s


Thanks everyone please check the below code sandbox link to check the custom promise execution

https://codesandbox.io/s/jovial-benji-qggtjn?file=/src/index.js

#frontend #frontendDevelopment #promise #poyfill

#webDevelopment #interview questions #interview tips #DevelopmentTips #UI #javascript #react #frontend interview



要查看或添加评论,请登录

Teja B的更多文章

社区洞察

其他会员也浏览了