Promises
Tags: webdev, javascript, programming, beginners
Published: 2023-06-26 17:40:57

## What is a Promise?

Promises are used to handle asynchronous operations introduced in `ES6`. It is an object that represents the eventual completion or failure of an asynchronous operation.

They are easy to manage when dealing with multiple asynchronous operations where callbacks can create callback hell leading to unmanageable code. Callback functions were used before promises, but they had limited functionality and resulted in unmanageable code. The nightmare that would result from having several callback functions would make the code unmanageable.

## Create a Promise

A promise is created using the `new` keyword, and it takes a function as an argument. This function takes two parameters, `resolve` and `reject`. The `resolve` function is called when the asynchronous operation is successful, and the `reject` function is called when the asynchronous operation fails.

```js
const promiseFunction = () => {
	new Promise((resolve, reject) => {
		// do something
		if (everythingIsOk) {
			resolve("success");
		} else {
			reject("failure");
		}
	});
};
```

## How to use a Promise?

A promise is used by calling the `then()` method on the promise object. The `then()` method takes two functions as arguments, the first function is called when the promise is resolved, and the second function is called when the promise is rejected.

```js
promiseFunction()
	.then((result) => {
		// if everyThingIsOK, and promise is resolved, then this function is called
	})
	.catch((error) => {
		// if something went wrong, and promise is rejected, then this function is called
	});
```

## States of a Promise

A promise (in JS context) takes some time to execute. There are possible `states` of a promise:

- `fulfilled`✅: Action related to the promise succeeded
- `rejected`❌: Action related to the promise failed
- `pending`⏳: Promise is still pending i.e. not fulfilled or rejected yet

As promise takes in two functions as parameters. That is, `resolve` and `reject` in declaring it.

Here is an example of a promise:

```js
const myPromise = new Promise((resolve, reject) => { // resolve and reject are functions
  if (/* condition */) {
    resolve("Promise was fulfilled ✅");
  } else {
    reject("Promise was rejected ❌");
  }
});
```

The `resolve` function is called when the promise is fulfilled and the `reject` function is called when the promise is rejected. The `resolve` and `reject` functions are called inside the promise. The `resolve` and `reject` functions are passed as parameters to the promise.

The `then()` method is used to handle the promise. It takes two functions as parameters. The first function is called when the promise is fulfilled ✅. The second function is called when the promise is rejected ❌.

```js
myPromise
	// highlight-start
	.then((value) => {
		console.log(value);
	})
	// highlight-end
	.catch((error) => {
		console.log(error);
	});
```

The `catch()` method is used to handle the promise when it is rejected ❌. It takes a function as a parameter. The function is called when the promise is rejected.

```js
myPromise
	.then((value) => {
		console.log(value);
	})
	.catch((error) => {
		console.log(error);
	});
```

## Examples

### Return a random number between 1 and 10

Let's create a promise that will return a random number between 1 and 10. If the number is greater than 5, the promise will be resolved, and if the number is less than 5, the promise will be rejected.

```js
const randomNumberGenerator = () => {
	new Promise((resolve, reject) => {
		const randomNumber = Math.floor(Math.random() * 10) + 1;
		if (randomNumber > 5) {
			resolve(randomNumber);
		} else {
			reject(randomNumber);
		}
	});
};

randomNumberGenerator()
	.then((result) => {
		console.log(`Success: ${result}`);
	})
	.catch((error) => {
		console.log(`Error: ${error}`);
	});
```

### Fetching Data from an API using Promises

```js
function getData() {
	return new Promise((resolve, reject) => {
		fetch("https://jsonplaceholder.typicode.com/todos/1")
			// Data will be assigned to the variable `response`, if the promise is fulfilled
			.then((response) => response.json())
			// ☝️ here we are converting the response to JSON, and returning it to the next `then` function
			.then((data) => resolve(data))
			// ☝️ here we are resolving the promise with the data
			.catch((error) => reject(error));
		// ☝️ here we are rejecting the promise with the error
	});
}

// Calling the function `getData`
getData()
	// 👇 `then()` will be called if the promise is resolved
	.then((data) => {
		console.log(data);
	})
	// 👇 `catch()` will be called if the promise is rejected
	.catch((error) => {
		console.log(error);
	});
```

In the above example, `getData()` is a function that returns a promise. It fetches the data from the API. The `then()` method is used to handle the promise when it is fulfilled. The `catch()` method is used to handle the promise when it is rejected.

## Promise Chaining

Promise chaining is a way to handle multiple promises. It is used to handle asynchronous operations in a better way. It is a replacement for callbacks and events. It is used to handle asynchronous operations in JavaScript, such as making HTTP requests to a server, reading from a file, or interacting with a database. They are easy to manage when dealing with multiple asynchronous operations where callbacks can create callback hell leading to unmanageable code. Callback functions were used before promises, but they had limited functionality and resulted in unmanageable code. The nightmare that would result from having several callback functions would make the code unmanageable.

```js
const promise1 = Promise.resolve("Promise 1 resolved");
const promise2 = new Promise((resolve, reject) => {
	setTimeout(() => {
		resolve("Promise 2 resolved");
	}, 2000);
});

promise1
	.then((value) => {
		// `value` will be "Promise 1 resolved"
		console.log(value);
		return promise2; // returning the `promise2` to the next `then` function
	})
	.then((value) => {
		// `value` will be "Promise 2 resolved"
		console.log(value);
	})
	.catch((error) => {
		console.log(error);
	});
```

In the above example, the `promise1` is resolved first. Then the `promise2` is resolved after 2 seconds. The `then()` method is used to handle the promise when it is fulfilled. The `catch()` method is used to handle the promise when it is rejected.

## `Promise.all()`

It takes an array of promises as an argument. It returns a single promise. It resolves when all of the promises in the argument array have resolved. It rejects with the reason of the first promise that rejects.

```js
const promise1 = Promise.resolve("Promise 1 resolved");
const promise2 = new Promise((resolve, reject) => {
	setTimeout(() => {
		resolve("Promise 2 resolved");
	}, 2000);
});

Promise.all([promise1, promise2])
	.then((values) => {
		console.log(values);
	})
	.catch((error) => {
		console.log(error);
	});
```

## `Promise.allSettled()`

It returns a promise that resolves after all of the given promises have either fulfilled or rejected, with an array of objects that each describes the outcome of each promise.

```js
const promise1 = Promise.resolve("Promise 1 resolved");
const promise2 = new Promise((resolve, reject) => {
	setTimeout(() => {
		resolve("Promise 2 resolved");
	}, 2000);
});

Promise.allSettled([promise1, promise2])
	.then((values) => {
		console.log(values);
	})
	.catch((error) => {
		console.log(error);
	});
```

## Conclusion

Here we have learned about promises in JavaScript. We have learned about the `Promise` object, the `then()` method, the `catch()` method, promise chaining, `Promise.all()`, and `Promise.allSettled()`. We have also learned about the examples of promises in JavaScript.