Skip to content
DeveloperMemos

Promises in JavaScript Explained

JavaScript, Promises, Asynchronous Programming1 min read

Asynchronous programming is a crucial aspect of modern web development. Handling asynchronous operations, such as making network requests or accessing data from databases, can be complex and error-prone. To simplify this process, JavaScript introduced the concept of promises. Promises are objects that represent the eventual completion or failure of an asynchronous operation. In this article, we will explore promises in JavaScript and learn how to leverage them effectively.

What are Promises?

A promise is an object that represents the result of an asynchronous operation. It can be in one of three states:

  1. Pending: The initial state when the asynchronous operation is still ongoing.
  2. Fulfilled: The state when the asynchronous operation is completed successfully.
  3. Rejected: The state when the asynchronous operation fails.

Creating Promises

To create a promise, we use the Promise constructor, which takes a function as its argument. This function, often referred to as the executor, receives two parameters: resolve and reject. Here's an example of creating a promise that resolves after a delay:

1const delay = (ms) => {
2 return new Promise((resolve, reject) => {
3 setTimeout(() => {
4 resolve('Operation completed successfully!');
5 }, ms);
6 });
7};
8
9delay(2000)
10 .then((result) => {
11 console.log(result);
12 })
13 .catch((error) => {
14 console.error(error);
15 });

In the above example, the delay function returns a promise that resolves with the message 'Operation completed successfully!' after the specified delay. We can then chain the then method to handle the fulfilled state and the catch method to handle any rejections.

Promise Chaining

Promises also allow us to chain multiple asynchronous operations together. This is achieved by returning a new promise from the then method. Let's take a look at an example:

1const fetchData = () => {
2 return new Promise((resolve, reject) => {
3 // Simulating an asynchronous network request
4 setTimeout(() => {
5 resolve({ name: 'John', age: 30 });
6 }, 2000);
7 });
8};
9
10fetchData()
11 .then((data) => {
12 console.log(`Name: ${data.name}`);
13 return new Promise((resolve, reject) => {
14 setTimeout(() => {
15 data.job = 'Developer';
16 resolve(data);
17 }, 2000);
18 });
19 })
20 .then((data) => {
21 console.log(`Name: ${data.name}, Age: ${data.age}, Job: ${data.job}`);
22 })
23 .catch((error) => {
24 console.error(error);
25 });

In the above example, the fetchData function simulates a network request and returns a promise. We then use the then method to handle the fulfilled state and return another promise that resolves after a delay. This allows us to perform subsequent operations on the data received from the initial promise.

Error Handling

Promises provide a convenient way to handle errors using the catch method. If any promise in the chain rejects, the catch method is called, allowing us to handle the error gracefully. Here's an example:

1const fetchData = () => {
2 return new Promise((resolve, reject) => {
3 // Simulating an asynchronous network request
4 setTimeout(() => {
5 reject('An error occurred while fetching the data.');
6 }, 2000);
7 });
8};
9
10fetchData()
11 .then((data) => {
12 console.log(`Data: ${data}`);
13 })
14 .catch((error) => {
15 console.error(error);
16 });

In the above example, the fetchData function simulates a network request that intentionally rejects with an error message. The catch method is then used to handle the rejection and log the error.

In Summary

  • Promises represent the eventual completion or failure of an asynchronous operation.
  • Promises can be created using the Promise constructor and the executor function.
  • Promise chaining allows you to perform sequential asynchronous operations.
  • Error handling in promises is achieved using the catch method.