Premium Javascript Course

JavaScript Promises

JavaScript promises are a powerful tool for handling asynchronous operations. A promise represents the eventual completion (or failure) of an asynchronous operation and its resulting value. In this lesson, we'll learn how to create, handle, and chain promises to handle asynchronous workflows effectively.

1. What is a Promise?

A promise is an object representing the eventual completion or failure of an asynchronous operation. It can be in one of three states:

2. Creating a Promise

To create a promise, we use the Promise constructor, which takes an executor function with two parameters: resolve and reject.

Basic Syntax of a Promise:


let myPromise = new Promise((resolve, reject) => {
    let success = true; // Simulate an asynchronous task

    if (success) {
        resolve("The task completed successfully!"); // Fulfilled
    } else {
        reject("The task failed!"); // Rejected
    }
});
        

The resolve function is called when the task completes successfully, and reject is called when there is an error or failure.

3. Handling Promise Results

Once a promise is created, we can use the then() and catch() methods to handle the resolved value or error, respectively.

Handling a Resolved Promise:


myPromise
    .then(result => {
        console.log(result); // "The task completed successfully!"
    })
    .catch(error => {
        console.error(error); // Will not run in this example
    });
        

In the example above, the then() method is called when the promise resolves successfully, and the result is logged to the console.

4. Chaining Promises

Promises can be chained using then() to perform multiple asynchronous operations sequentially. Each then() returns a new promise.

Example of Chaining Promises:


let firstTask = new Promise((resolve, reject) => {
    setTimeout(() => resolve("First task done!"), 1000);
});

firstTask
    .then(result => {
        console.log(result); // "First task done!"
        return new Promise(resolve => setTimeout(() => resolve("Second task done!"), 1000));
    })
    .then(result => {
        console.log(result); // "Second task done!"
    });
        

In this example, the second promise is created inside the first then() method and chained to the next then().

5. Promise.all

If you need to run multiple asynchronous tasks concurrently and wait for all of them to complete, use Promise.all(). This method returns a single promise that resolves when all the provided promises are resolved, or rejects when any one of them fails.

Example of Promise.all:


let promise1 = new Promise(resolve => setTimeout(() => resolve("Task 1 completed"), 1000));
let promise2 = new Promise(resolve => setTimeout(() => resolve("Task 2 completed"), 1500));
let promise3 = new Promise(resolve => setTimeout(() => resolve("Task 3 completed"), 500));

Promise.all([promise1, promise2, promise3])
    .then(results => {
        console.log(results); // ["Task 1 completed", "Task 2 completed", "Task 3 completed"]
    })
    .catch(error => {
        console.error("An error occurred:", error);
    });
        

In this example, Promise.all() waits for all three promises to resolve and then executes the then() block.

6. Promise.race

If you need to perform multiple asynchronous tasks but only care about the first one to resolve (or reject), use Promise.race(). It returns a promise that resolves or rejects as soon as one of the provided promises resolves or rejects.

Example of Promise.race:


let promise1 = new Promise(resolve => setTimeout(() => resolve("Task 1 completed"), 2000));
let promise2 = new Promise(resolve => setTimeout(() => resolve("Task 2 completed"), 1000));

Promise.race([promise1, promise2])
    .then(result => {
        console.log(result); // "Task 2 completed"
    })
    .catch(error => {
        console.error(error);
    });
        

In this case, Promise.race() resolves with the first promise that completes, so the result is "Task 2 completed" because it finished first.

7. Error Handling in Promises

Promises can be rejected, and error handling can be done using catch() method. It is crucial to handle errors to avoid unhandled rejections, which can lead to bugs and unexpected behavior.

Example of Error Handling:


let myPromise = new Promise((resolve, reject) => {
    let success = false;

    if (success) {
        resolve("Task completed successfully!");
    } else {
        reject("Something went wrong!");
    }
});

myPromise
    .then(result => console.log(result))
    .catch(error => console.error(error)); // "Something went wrong!"
        

In this example, if the promise is rejected, the catch() method will handle the error and log it to the console.

8. Conclusion

JavaScript promises are a powerful way to handle asynchronous operations. By using promises, you can avoid callback hell and handle asynchronous flows in a more structured way. Whether you use simple promises, promise chaining, Promise.all, or Promise.race, they allow you to manage asynchronous operations more effectively and with better error handling.