Understanding JavaScript Promises

Understanding JavaScript Promises

Introduction

JavaScript promises are a powerful addition to language.

In web development, dealing with asynchronous operations is inevitable. Whether it’s fetching data from a server, reading files, or executing time-consuming computations, JavaScript developers often find themselves in scenarios where they need to handle tasks that don’t complete instantly.

This is where understanding JavaScript promises come into play.

In this blog post, we’ll delve deep into what JavaScript promises are and how to use them, accompanied by practical code examples.

What is a JavaScript Promise?

A Promise in JavaScript is an object representing the eventual completion (or failure) of an asynchronous operation. Essentially, it’s a placeholder for a value that will be available in the future.

Promises help you manage asynchronous operations more efficiently, allowing you to write cleaner, more readable, and maintainable code.

Promises have three states:

  1. Pending: The initial state of a promise. The operation has not completed yet.
  2. Fulfilled: The operation completed successfully.
  3. Rejected: The operation failed.

Creating a Promise

Let’s start with creating a basic promise.

const myPromise = new Promise((resolve, reject) => {
    const condition = true;
    if (condition) {
        resolve('Promise is resolved successfully.');
    } else {
        reject('Promise is rejected.');
    }
});

myPromise.then(result => console.log(result))
         .catch(error => console.log(error));

In this example, myPromise is a new Promise. It takes a function with two parameters: resolve and reject. If the condition is true, the promise is resolved; otherwise, it’s rejected. The .then() method is used to handle the fulfilled state, and .catch() is for handling rejection.

Handling Asynchronous Operations

Promises really shine when handling asynchronous operations, such as API calls. Here’s an example using the Fetch API:

fetch('https://jsonplaceholder.typicode.com/posts/1')
    .then(response => response.json())
    .then(data => console.log(data))
    .catch(error => console.error('Error:', error));

Here, fetch() returns a promise. We chain .then() to handle the response, converting it to JSON, and then another .then() to work with the actual data. .catch() is used to handle any errors.

Chaining Promises

Promises can be chained, which is powerful for sequential asynchronous operations:

const cleanRoom = () => {
    return new Promise((resolve, reject) => {
        resolve('Cleaned The Room');
    });
};

const removeGarbage = message => {
    return new Promise((resolve, reject) => {
        resolve(`${message} then removed the Garbage`);
    });
};

const winIcecream = message => {
    return new Promise((resolve, reject) => {
        resolve(`${message} then won an icecream`);
    });
};

cleanRoom()
    .then(result => removeGarbage(result))
    .then(result => winIcecream(result))
    .then(result => console.log(`Finished: ${result}`));

In this example, each function returns a promise. After cleaning the room, the garbage is removed, and then the icecream is won, demonstrating a sequence of actions.

Error Handling in Promise Chains

Error handling in promise chains is crucial. If any promise in the chain is rejected, the control jumps to the nearest .catch():

cleanRoom()
    .then(result => removeGarbage(result))
    .then(result => winIcecream(result))
    .then(result => console.log(`Finished: ${result}`))
    .catch(error => console.log(`Error: ${error}`));

Here, if any of the promises gets rejected, the error will be caught and logged.

Promise.all

When you need to run multiple promises in parallel and wait for all of them to complete, Promise.all is very useful:

Promise.all([cleanRoom(), removeGarbage(), winIcecream()])
    .then(() => console.log("All tasks completed successfully"))
    .catch(error => console.log(`Error in completing tasks: ${error}`));

In this case, Promise.all takes an array of promises and returns a new promise that resolves when all the promises in the array are resolved.

Conclusion

Promises in JavaScript are a powerful tool for managing asynchronous operations, making your code cleaner and easier to maintain.

They allow you to handle operations that occur in the background and may take some time to complete, such as API requests or file operations.

By mastering promises, you can ensure your JavaScript applications are efficient, readable, and robust.

Remember, good error handling is essential to make your application resilient and reliable.

Some great documentation for JavaScript promises can be found here: – https://www.w3schools.com/js/js_promise.asp

I have a great post about the same technique with TypeScript here: – Understanding TypeScript Promises

Stephen

Hi, my name is Stephen Finchett. I have been a software engineer for over 30 years and worked on complex, business critical, multi-user systems for all of my career. For the last 15 years, I have been concentrating on web based solutions using the Microsoft Stack including ASP.Net, C#, TypeScript, SQL Server and running everything at scale within Kubernetes.