Table of contents
- Introduction
- Promise structure
- What should happen when we call the new promise function?
- Achieving this functionality
- Important Properties of Promise
- Custome mypromise till now
- We need to store the status of the promise,how to do that
- Another important property of promise
- Important property number 3 of promise
- Important property of promise .then
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
- Pending
- Resolved
- 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
- 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
- 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
- A callback function resolve_callback when we call the resolve method of the promise which can be determined from the state of the promise
- A callback function reject_callback when we call the reject method of the promise which can be determined from the state of the promise.
- 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;
}
}