All about JavaScript promises
Tags: javascript, beginners, learning
Published: 2023-04-25 19:35:07

## Introduction

<div align="justify">

Javascript promise is a object representing eventual completion or failure of an asynchronous operation. It allows you to associate handlers with asynchronous methods: instead of immediately returning a value, the asynchronous methods returns a promise to return value at some point in future.

_OR_

JavaScript promises are a way to handle asynchronous code in a more organized and intuitive way.When you have an asynchronous operation that takes some time to complete, like making an API call or fetching data from a server, you don't want your program to be blocked waiting for the operation to finish. Instead, you want to continue running other code and then handle the result of the asynchronous operation when it's ready.

</div>

> **Questions to ask yourself**
> 
> Question 1: What are JavaScript promises used for?
> 
>a) Handling synchronous code
>
>b) Handling asynchronous code
>
>c) Both a and b
>
>d) None of the above

## Part 2: Promise States

<div align="justify">
Promises provide a way to handle asynchronous code by encapsulating the 
asynchronous operation and providing a way to handle the result when it's ready. A promise is an object that represents a value that may not be available yet. It has three states:
</div>

   - **Pending** :  The initial state, before the asynchronous operation is complete.
   - **Fulfiled** : The operation completed successfully, and the result is available.
   - **Rejected** : The operation failed, and a error message is available.

> **Questions to ask yourself**
> 
> Question 2: How many states does a JavaScript promise have?
> 
>a) 1
>
>b) 2
>
>c) 3
>
>d) None of the above
> 
> Question 3: What is the initial state of a JavaScript promise?
> 
>a) Fulfilled
>
>b) Rejected
>
>c) Pending
>
>d) None of the above
>

## Part 3: Creating and using promises

<div align="justify">
You can create a new promise using the Promise constructor. The constructor takes a single argument, a function that takes two parameters: resolve and reject. Inside this function, you can perform your asynchronous operation, and then call either the resolve function if the operation succeeds, or the reject function if it fails.
</div>

Here's an syntax example of creating a promise:

```JS
let myPromise=new Promise(function(resolve,reject)=>{
   //"Producing code" (May take some time)

   resolve();// When successful

   reject() // When failed
})
```
In here, **resolve** and **reject** are functions that bring promise life cycle to completion. When the producing code obtains the result, it should be one of this two callbacks:

   `resolve(resultValue)` if successful.

   `reject(errorObject)` if there is an error.

Here's an example of creating a promise that resolves after delay:

```JS
const myPromise=new Promise((resolve,reject)=>{
   setTimeout(()=>{
      resolve('Success)
   },1000)
})
```

### Handling a fulfilled or Rejected Promise:

<div align="justify">
Once you have a promise, you can use the **then** method to handle the result when it's ready. The then method takes a single argument, a function that will be called with the result when the promise is fulfilled.
</div>

```JS
myPromise.then(result => {
  console.log(result); // Output: Success!
});
```

You can also use the catch method to handle errors when a promise is rejected.

```JS
myPromise.catch(error=>{
   console.log(error)
})
```

>**Question 5: What does the Promise constructor take as an argument?**
>
>
>
>a) A function that takes one parameter
>
>b) A function that takes two parameters: resolve and reject
>
>c) A string
>
>d) An object
>
>**Question 6: What method do you use to handle the result of a fulfilled promise?**
>
>
>a) then
>
>b) catch
>
>c) resolve
>
>d) reject
>
>**Question 7: What method do you use to handle errors when a promise is rejected?**
>
>
>a) then
>
>b) catch
>
>c) resolve
>
>d) reject

## Part4: Chaining Promises:

<div align="justify">

You can chain promises together to perform a series of asynchoronous operations in a specific order using the `then()` and `catch()` methods. These methods are used to associate further action with promise that becomes settled. As these methods return promises, they can be chained.

</div>

Here's an example of chaining multiple promises:

```JS
let myPromise=new Promise((resolve,reject)=>{
   //"Producing code" (May take some time)
   resolve() //When successful

   reject() //when failed
})

myPromise
   .then(function(value){
      // If code successful
      return anotherPromise
   })
   .then(function(anotherValue){
      // If code successful
      return yetAnotherPromise
   })
   .catch(function(error){
      // Code if some error
   })
```

Another example of chaining promises:

```JS

const firstPromise = new Promise((resolve, reject) => {
  
  setTimeout(() => {
    resolve('First promise resolved.');
  }, 1000);

});

const secondPromise = firstPromise.then(result => {
  
  console.log(result); // Output: First promise resolved.

  return 'Second promise resolved.';
});

secondPromise
   .then(result => {
      console.log(result); // Output: Second promise resolved.
   })
   .catch(err=>{
      console.log(error)
   })

```

>If there is no catch method in the code snippet provided. When an error occurred in the code, it would be thrown as an unhandled exception, and depending on the context, it may crash the application or be caught by a higher-level error handler. It's important to include catch methods in your promise chains to properly handle errors and avoid unhandled exceptions.


<div align="justify">

In the example above, we create a new promise secondPromise by calling then on the firstPromise. Inside the then function, we log the result of the first promise, and then return a new value, 'Second promise resolved.'. We can then chain another then method to handle the result of the secondPromise.

</div>

>**Question 8: How do you chain promises together?**
>
>
>a) By calling the then method on a promise and returning a new promise from inside the then function
>
>b) By calling the catch method on a promise and returning a new promise from inside the catch function
>
>c) By calling the finally method on a promise and returning a new promise from inside the finally function

## Part 5: Promise.all and Promise.race

<div align="justify">

`Promise.all` and `Promise.race` are methods that allow you to handle multiple promises simultaneously.

`Promise.all` takes an array of promises and returns a new promises that resolves when all of the promises in the array resolved. The new promise's resolved value is an array of resolved values of each promise.

```JS
const promises=[
   new Promise(resolve => setTimeout(() => resolve(1), 3000)),
   new Promise(resolve => setTimeout(() => resolve(2), 2000)),
   new Promise(resolve => setTimeout(() => resolve(3), 1000))
]

Promise.all(promises).then(results=>{
   console.log(results) // Output :[1, 2, 3]
})
```

In the example above, we create an array of promises that resolve after different intervals. We pass this array to `Promise.all` and use the `then` method to log the resolved values.

> **Wondering why the output for this code is [1,2,3]  not [3,2,1]?**
>
> The output of [1, 2, 3] is because Promise.all waits for all promises to resolve before resolving the new promise it returns. In this example, the first promise in the array takes 3 seconds to resolve, the second promise takes 2 seconds to resolve, and the third promise takes 1 second to resolve.
>
>However, since we passed an array of promises to Promise.all, it will wait for all promises to resolve before the then method is called. Therefore, the resolved values of each promise are collected in an array and returned in the order they were provided in the original array of promises.
>
>So in this case, the promise that resolves in 3 seconds resolves last and its resolved value of 1 is placed first in the results array, followed by the promise that resolves in 2 seconds with a resolved value of 2, and finally, the promise that resolves in 1 second with a resolved value of 3.


`Promise.race` takes an array of promises and returns a new promise that resolves or rejects as soon as one of the promises in the array resolves or rejects. The new promise's resolved or rejected value is the resolved or rejected value of the first promise that resolves or rejects.

```JS
const promises = [
  new Promise(resolve => setTimeout(() => resolve(1), 3000)),
  new Promise((resolve, reject) => setTimeout(() => reject(new Error('Error')), 2000)),
  new Promise(resolve => setTimeout(() => resolve(3), 1000))
];

Promise.race(promises).then(result => {
  console.log(result); // Output: Error: Error
});

```

In the example above, we create an array of promises that resolve or reject after different intervals. We pass this array to `Promise.race` and use the `then` method to log the resolved or rejected value of the first promise.

</div>

## Bonus Question:

Conside the following code:

```JS
async function getData() {
  const response = await fetch('https://jsonplaceholder.typicode.com/users');
  const data = await response.json();
  return data;
}

console.log(getData());

```

>What will be logged to the console and why?
>
>a) A Promise object will be logged to the console because console.log is called before the getData function finishes executing.
>
>b) An error will be thrown because the fetch method cannot be used in an async function.
>
>c) An object representing the data retrieved from the API will be logged to the console because the await keyword ensures that the getData function waits for the fetch method to resolve before returning the data.
>
>d) Undefined will be logged to the console because the getData function does not have a return statement.


<details>

 The answer for the bonus question is **c) An object representing the data retrieved from the API will be logged to the console because the `await` keyword ensures that the `getData` function waits for the `fetch` method to resolve before returning the data.**.

Explanation:

The `getData` function is an asynchronous function that sends an HTTP GET request to an API endpoint using the `fetch` method. The `await` keyword is used to wait for the response from the API to be returned before the `response.json()` method is called. This method parses the response body as JSON and returns a JavaScript object representing the data. Finally, the `getData` function returns the parsed data.

The `console.log(getData())` statement logs the return value of the `getData` function to the console. Since the `getData` function is an asynchronous function that returns a promise, the `console.log` statement logs a promise object to the console. However, since the `await` keyword ensures that the function waits for the `fetch` method to resolve before returning the data, the resolved data object will be logged to the console.
</details>