JS Promises Simplified!!!
Tags: webdev, javascript, beginners, tutorial
Published: 2023-10-30 06:15:48

## What are Promises ?

promises are objects that represent the eventual completion or failure of an async task!!. 
(Assume the Promise is just as "Promise" from plain English language.). 

> "😎 JavaScript promises are more reliable than the promises that your partner made"

When you create a promise, it will be in one of the following states:

1. **Pending**: The initial state of the Promise before it is fulfilled or rejected.
2. **Fulfilled**: The state of the Promise representing a successful operation.
3. **Rejected**: The state of the Promise representing a failed operation

>If your partner promises you that "we will be together"💕 consider this as a **Pending** promise🤞, However he/she dumps💩 you then consider it as **Rejected** promise😭. But if he/she was a green flag and finally you both get married💑 then it is a **Fulfilled** promise😎.


You can create new promise using the `Promise` constructor, and you can attach callbacks to it using the `.then()` and `.catch()` methods to handle the resolved value or the error, respectively.
Here is a syntax to create a promise!! . Try running this code itself
```js
const promise = new Promise((resolve,reject)=>{
//console.log("Try to run me before writing last line see what happens!!")
  resolve("Success!!!")
})

promise.then(data=>console.log(data))
```
Also, Let me know that if we uncomment the second line, and simply run the code after declaring promise, 

Another example with a rejected promise!!!
```js
const promise = new Promise((resolve,reject)=>{
  
  setTimeout(()=>{
    
  reject("Failure!!!")
  },3000)
})

promise.then(data=>console.log(data)).catch(err=>console.error(err))
```

> **TASK :** Can you write a relationship promise ? prompt a question "Do you want to marry me ?" If the user inputs "Yes" then the promise must be fulfilled after- 3 sec. and if user inputs "No" then the promise should rejects! (Challenge :- Try to make it with the DOM Manipulation A Input and Button Ask and reply should be below!!, You can also get creative if you want.)


### Advance Concepts of Promises.

There are also some Techniques to optimize the performance. You can try them below
Here's a breakdown of the differences between `Promise.all`, `Promise.allSettled`, and `Promise.race`:

1.**Promise.all:**
    
 - It takes an iterable of promises as an input.
 - Resolves when all the promises in the iterable have resolved.
 - If any promise rejects, the entire `Promise.all` call is rejected immediately with the reason of the first rejected promise.
 - Returns an array of the resolved values in the same order as the input promises.
      
2.**Promise.allSettled:**
    
    - It takes an iterable of promises as an input.
    - Resolves when all the promises in the iterable have either resolved or rejected.
    - It does not short-circuit when a promise rejects, and it waits for all the promises to settle before resolving.
    - Returns an array of objects representing the outcome of each promise, including a `status` property indicating whether the promise was fulfilled or rejected, along with a `value` or `reason` property.
      
3.**Promise.race:**
    
    - It takes an iterable of promises as an input.
    - Resolves or rejects as soon as one of the promises in the iterable resolves or rejects.
    - Returns the value or reason from the first settled promise.
    - It does not wait for all promises to settle and can be used to implement a timeout feature or race conditions between different asynchronous operations.

These methods provide different ways of handling multiple promises, allowing you to manage asynchronous operations effectively depending on your specific use case.


**`Promise.all` Another Example**
```js
let job = (delay)=>{
  return new Promise((resolve)=>{
    setTimeout(()=>{
      console.log("message : "+ delay)
      resolve(delay)
    }, delay)
  })
}

Promise.all([job(5000), job(2000), job(3000)]).then(data=>{ console.log("printing : \n"); data.forEach(item=>console.log(item))}).catch(err=>console.log(err))

//Output : 
//message : 2000
//message : 3000
//message : 5000
//printing :
//5000
//2000
//3000
```

**`Promise.all` fails if any one of the promise fails Example : **
```js
let p1 = new Promise(function(resolve, reject) {
    setTimeout(resolve, 500, 'p1');
});

let p2 = new Promise(function(resolve, reject) {
    setTimeout(resolve, 1000, 'p2');
});

let p3 = new Promise(function(resolve, reject) {
    setTimeout(resolve, 1200, 'p3');
});

let p4 = new Promise(function(resolve, reject) {
    setTimeout(reject, 300, 'p4');
});

let p5 = new Promise(function(resolve, reject) {
    setTimeout(resolve, 800, 'p5');
});

let p6 = new Promise((resolve, reject)=>{
  resolve('P6')
})
let promise = Promise.all([p1, p2, p3, p4, p5, p6]);

promise

.then(function(data) {
    data.forEach(function(data) {
        console.log(data);
    });
})

.catch(function(error) {
    console.error('error', error);
});

//Output
//Error: error p4
```
Now there is one thing can be done in order to avoid short circuiting is. To use `promise.allSettled` but Then it will log the settled promises as an object.
or Alternatively all `promise.all` with each catch calls like following
```js
let promise = Promise.all([p1.catch(()=>{}), p2.catch(()=>{}), p3.catch(()=>{}), p4.catch(()=>{}), p5.catch(()=>{}), p6.catch(()=>{})]);

//output
//p1
//p2
//p3
//undefined
//p5
//P6
```

In the same above example let us use the `promise.race`
```js
let promise = Promise.race([p1, p2, p3, p4, p5, p6]);
promise
.then(function(data) {
        console.log(data);
})

.catch(function(error) {
    console.error('error', error);
});

//Output
P6
```



### Promise Chaining

consider the following code
```js
var promise = job1();

promise
.then(function(data1) {
    console.log('data1', data1);
    return job2();
})
.then(function(data2) {
    console.log('data2', data2);
    return 'Hello world';
})
.then(function(data3) {
    console.log('data3', data3);
}).then(data=>console.log(data));

function job1() {
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            resolve('result of job 1');
        }, 1000);
    });
}

  
function job2() {
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            resolve('result of job 2');
        }, 1000);
    });
}

///Output
//data1 result of job 1
//data2 result of job 2
//data3 Hello world
//undefined
```
- We call `job1` and we store the returned promise in a variable called `promise`.
-  We call `then` on this promise and we attach a callback for when the promise is resolved
-  We print `data1` and it is obvioulsy `result of job 1` 
-  we call `job2` and we return the resulting promise. 
- We call `then` on the result of the first `then`. The result of `then` is always a promise. _Always._ At worst, it can be a never resolved promise, but it is a promise. In this case, the promise is the return value of `job2` . When you are in a `then` callback, if you return a promise, it will be the resulting promise of the `then` call.
-  We print `data2`. According to the `resolve` call in the promise returned by `job2` , `data2` is `result of job 2` . By chaining our 2 promises (`job1` then `job2`), `job2` is always executed after `job1`. 
- We return a simple string `'Hello world'`.
-  We call `then` on the result of the `then` call . The promise here is an auto-resolved promise, and it will pass `'Hello world'` in the data. When you are in a `then` callback, if you return anything but a promise, an auto-resolved promise is created, and this promise will be the result of the `then` call.
-  We print `data3` and this is the `'Hello world'` will return.

### The Broken Chain !

```js
function test() { 
	var promise = job(); 
	promise.then(function(data) { 
		doSomething(data); 
		}); 
	return promise; 
}
```

In this code the `promise.then` is not returned, in-fact the function test returns the initial promise. and therefore the result of the `promise.then` is lost. Because there is no one can interact with it.

How to fix it?
```js
function test() { 
	return job().then(function(data) { 
		doSomething(data); 
		});  
}
```

### Creating auto Resolve and auto Reject promises
```js
function job() { 
	if (test) { 
	return aNewPromise(); 
	} else { 
	return Promise.resolve(42); // return an anto-resolved promise with `42` in  data. 
	} 
}
```
`Promise.resolve(42)` Auto-resolve promise
`promise.reject('error')` Auto reject promise

> As a rule of thumb 👍: whenever a function can return a promise, ALWAYS return a promise.

success defeat error Error caught

### Test Example to test Chaining with Catch

```js
function job(state) {
    return new Promise(function(resolve, reject) {
        if (state) {
            resolve('success');
        } else {
            reject('error');
        }
    });
}

let promise = job(true);

promise

.then(function(data) {
    console.log(data);

    return job(true);
})

.then(function(data) {
    if (data !== 'victory') {
        throw 'Defeat';
    }

    return job(true);
})

.then(function(data) {
    console.log(data);
})

.catch(function(error) {
    console.log(error);

    return job(false);
})

.then(function(data) {
    console.log(data);

    return job(true);
})

.catch(function(error) {
    console.log(error);

    return 'Error caught';
})

.then(function(data) {
    console.log(data);

    return new Error('test');
})

.then(function(data) {
    console.log('Success:', data.message);
})

.catch(function(data) {
    console.log('Error:', data.message);
});


//Output:
//success, Defeat, error, Error caught, Success: test
```

So as per my understanding based on the example above. Promise is resolve it goes to the success callback function chained with .then function(). But if promise is rejected and the error is thrown by means of throw new Error or throw Error, Then it is caught by the catch block. 
Now if the catch block returns anything, then the chaining continues with the .then callback function but if catch block throws error then it will be caught by the next catch block.
Also if the promise is rejected then the catch block is executed with the error message.