PROMISE Without using promise.util class

PROMISE Without using promise.util class

Introduction

Promises in JavaScript represent processes that are already happening, which can be chained with callback functions.

Promise structure

when we write new promise we pass an executor function as a parameter to the promise

new Promise((resolve,reject)=>{

//this is the executor function 

}

It is this executor function which is called the body of the promise The executor function passed will also have two parameters resolve and reject Both these functions are callbacks that are passed into executor function . The implementation of this parameter is hidden from the user. The implementation of both resolve and reject are hidden from the user, they get bound when we create the promise object As we know a promise has three states

  1. Pending
  2. Resolved
  3. Rejected When we call the resolve function internally the resolve function will set the state to Resolved state and pass the value. When we call the reject function internally the reject function will set the state to rejected state and pass the value.

What should happen when we call the new promise function?

Automatically the executor function should get called. How to achieve this functionality

Achieving this functionality

When we create an a instance of an object the constructor function gets called automatically So what we can do is we can pass this executor function within the constructor

class MyPromise{
constructor(executorfunc)  {

}


}

We need to handle when to pass resolve and when to pass reject to the executor function One of the important properties of promise is that in case of an error the executor function with reject parameter is called We know if we want to try to check if the code has error or not we use the try-catch block in javascript The way it works is in case of no error we run the try block in case of an error we call the catch block

Important Properties of Promise

Only the then and catch method are methods which can be accessed outside of the class. How to strict the scope of a block to the class. In es6 abstraction, an important pillar of object-oriented programming was introduced. Until then we used to assume that the variables named with leading _ are private methods. After ES6 all methods and variables declared with a leading # are considered as private.

Custome mypromise till now

        class myPromise{
  constructor(executorFunc) {
    try {
      executorFunc(
        value => this.#resolve(value),//this is binding this with resolve function call
        value => this.#reject(value),// this is binding this with reject function call
      );
    } catch (error) {
      this.#reject(error);
    }
  }
}

We need to store the status of the promise,how to do that

We create an object of all possible status

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

this is such that we can access it anywhere outside or inside the class hence we declare it in the window scope

Another important property of promise

We can not access the current status of the promise hence inside the class we declare a private variable indicating the state and other indicating the value Also the moment we create an instance of the mypromise class the state should be set to pending

#state = STATE.PENDING;
  #value = null;

Our mypromise class until now will look like

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

class MyPromise {

  #state = STATE.PENDING;
  #value = null;
  constructor(executorFunc) {
    try {
      executorFunc(
        value => this.#resolve(value),
        value => this.#reject(value),
      );
    } catch (error) {
      this.#reject(error);
    }
  }

Important property number 3 of promise

We know that the resolve and reject methods are private. But what they are doing is

  1. When reject or resolved is called depending on what is called we need to set state, so now we will implement those methods but they will be private in nature

So now our mypromise class will look like

  'PENDING':'pending',
  'FULFILLED':'fulfilled',
  'REJECTED':'rejected',
}

class MyPromise {

  #state = STATE.PENDING;
  #value = null;
  constructor(executorFunc) {
    try {
      executorFunc(
        value => this.#resolve(value),
        value => this.#reject(value),
      );
    } catch (error) {
      this.#reject(error);
    }

 #resolve(value){

  this.#value=value;
  this.#state=STATE.FULFILLED;

  }

  #reject(value){


    this.#value=value;
    this.#state=STATE.REJECTED;

  }


  }

Important property of promise .then

  1. The .then method is the only method which we can access from outside . If we need to access the parameter passed to private resolve and reject method we use .then. When calling the then method then it should return us a new promise Also, we pass two parameters to the then method
  2. A callback function resolve_callback when we call the resolve method of the promise which can be determined from the state of the promise
  3. A callback function reject_callback when we call the reject method of the promise which can be determined from the state of the promise.
  4. Note: If one or both arguments are omitted or are provided non-functions, then then will be missing the handler(s), but will not generate any errors. If the Promise that then is called on adopts a state (fulfillment or rejection) for which then has no handler, the returned promise adopts the final state of the original Promise on which then was called. We need to handle this situation as well

Now our implementation will look like


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


class MyPromise {
  // Write your code here.
  #state = STATE.PENDING;
  #value = null;

  constructor(executorFunc) {
    try {
      executorFunc(
        value => this.#resolve(value),
        value => this.#reject(value),
      );
    } catch (error) {
      this.#reject(error);
    }
  }

  then(onFulfilled, onRejected) {
    // Write your code here.
        return new MyPromise((resolve,reject)=>{

          const fulfilledCallback=()=>{
            if(!onFulfilled) return resolve(this.#value);//case where we dont have a function passed to .then     
                       method
              queueMicrotask(()=>{// this is additional as of now, we need to study event handlers for this
                try {
                  const value =  onFulfilled(this.#value);
                  resolve(value);
                } catch (error) {
                  reject(error);
                }
              }) ;
          };

          const rejectedCallback = () => {
          if(!onRejected) return reject(this.#value);
            queueMicrotask(()=>{ // this is additional as of now, we need to study event handlers for this
                try {
                  const value = onRejected(this.#value);
                  resolve(value);
                } catch (error) {

                  reject(error);

                }    
            });
          };
          switch(this.#state){// this is the state machine which calls the respective function based on their 
                                                 states
           case STATE.PENDING:
              this.#fulfilledCallbacks.push(fulfilledCallback);
              this.#rejectedCallbacks.push(rejectedCallback);
              break;

            case STATE.FULFILLED:
              fulfilledCallback();
              break;
            case STATE.REJECTED:
              rejectedCallback();
              break;
            default:
              throw new Error('Unexpected promise state')

          }
        });





  }

  catch(onRejected) {
    // Write your code here.
    return this.then(null,onRejected);
  }

  get state() {
    return this.#state;
  }

  get value() {
    // Write your code here.
    return this.#value;
  }



  #resolve(value){

  this.#value=value;
  this.#state=STATE.FULFILLED;

  }

  #reject(value){


    this.#value=value;
    this.#state=STATE.REJECTED;

  }

}