Introduction

A JavaScript Promise is a special object that makes handling asynchronous tasks much easier. Instead of blocking the program while waiting for something like an API response, file load, or a timer, Promises act as placeholders for values that will become available later. Once the operation completes, the Promise either provides the result or an error.

Think of a Promise as a deal: it either fulfills its promise (success) or fails to do so (failure).

States of a Promise

A Promise can be in one of three states:

  1. Pending – The task is still in progress and has not yet finished.

  2. Fulfilled – The task completed successfully, and a result is available.

  3. Rejected – The task failed, and an error is returned.

Once a Promise is either fulfilled or rejected, it is considered settled, and its result does not change.

Example: Checking if a Number is Even

JavaScript
let checkEven = new Promise((resolve, reject) => {
    let number = 4;
    if (number % 2 === 0) resolve("The number is even!");
    else reject("The number is odd!");
});

checkEven
    .then((message) => console.log(message)) // Runs if resolved
    .catch((error) => console.error(error));  // Runs if rejected

📌 Note: resolve and reject are not keywords; you can name them anything.

General Syntax of a Promise

JavaScript
let promise = new Promise((resolve, reject) => {
    // Perform some async operation
    if (operationSuccessful) {
        resolve("Task successful");
    } else {
        reject("Task failed");
    }
});

Advanced Promise Methods and Patterns

1. Promise.all()

Runs multiple promises in parallel and waits until all succeed. If any fail, it rejects immediately.

JavaScript
Promise.all([
    Promise.resolve("Task 1 done"),
    Promise.resolve("Task 2 done"),
    Promise.reject("Task 3 failed")
])
    .then((results) => console.log(results))
    .catch((error) => console.error(error));

Output:

Code
Task 3 failed

2. Promise.allSettled()

Runs all promises and returns results for both fulfilled and rejected ones.

JavaScript
Promise.allSettled([
    Promise.resolve("Task 1 done"),
    Promise.reject("Task 2 failed"),
    Promise.resolve("Task 3 done")
])
    .then((results) => console.log(results));

Output:

Code
[
  { status: 'fulfilled', value: 'Task 1 done' },
  { status: 'rejected', reason: 'Task 2 failed' },
  { status: 'fulfilled', value: 'Task 3 done' }
]

3. Promise.race()

Returns the result of the first promise that settles (success or failure).

JavaScript
Promise.race([
    new Promise((resolve) => setTimeout(() => resolve("Task 1 finished"), 1000)),
    new Promise((resolve) => setTimeout(() => resolve("Task 2 finished"), 500))
])
.then((result) => console.log(result));

Output:

Code
Task 2 finished

4. Promise.any()

Resolves as soon as the first promise is fulfilled. Rejects only if all fail.

JavaScript
Promise.any([
    Promise.reject("Task 1 failed"),
    Promise.resolve("Task 2 done"),
    Promise.resolve("Task 3 done")
])
    .then((result) => console.log(result))
    .catch((error) => console.error(error));

Output:

Code
Task 2 done

5. Promise.resolve()

Creates a promise that resolves immediately with a given value.

JavaScript
Promise.resolve("Immediate success")
    .then((value) => console.log(value));

Output:

Code
Immediate success

6. Promise.reject()

Creates a promise that rejects immediately.

JavaScript
Promise.reject("Immediate failure")
    .catch((error) => console.error(error));

Output:

Code
Immediate failure

7. Promise.finally()

Runs cleanup code after a promise settles, regardless of success or failure.

JavaScript
Promise.resolve("Task completed")
    .then((result) => console.log(result))
    .catch((error) => console.error(error))
    .finally(() => console.log("Cleanup completed"));

Output:

Code
Task completed
Cleanup completed

8. Promise Chaining with .then()

Allows sequential operations.

JavaScript
Promise.resolve(5)
    .then((value) => value * 2)  // 10
    .then((value) => value + 3)  // 13
    .then((finalValue) => console.log(finalValue));

Output:

Code
13

9. Sequential Execution with reduce()

Using .reduce() to process tasks in sequence.

JavaScript
let tasks = [1, 2, 3];
tasks.reduce((prevPromise, current) => {
    return prevPromise.then(() => {
        return new Promise((resolve) => {
            console.log(`Processing task ${current}`);
            setTimeout(resolve, 500);
        });
    });
}, Promise.resolve());

Output:

Code
Processing task 1
Processing task 2
Processing task 3

10. Dynamic Promise Creation

Creating promises based on runtime conditions.

JavaScript
function asyncTask(taskName) {
    return new Promise((resolve) => {
        setTimeout(() => resolve(`${taskName} completed`), 1000);
    });
}

asyncTask("Download File")
    .then((result) => console.log(result));

Output:

Code
Download File completed

11. Timeout Handling with Promise.race()

Set a timeout limit for an async task.

JavaScript
let fetchData = new Promise((resolve) => setTimeout(() => resolve("Data loaded"), 3000));
let timeout = new Promise((_, reject) => setTimeout(() => reject("Timeout!"), 2000));

Promise.race([fetchData, timeout])
    .then((result) => console.log(result))
    .catch((error) => console.error(error));

Output:

Code
Timeout!

12. Handling Multiple Failures with Promise.allSettled()

Useful when you need to see results of all tasks, even failed ones.

JavaScript
Promise.allSettled([
    Promise.resolve("Task 1 done"),
    Promise.reject("Task 2 failed"),
    Promise.resolve("Task 3 done")
])
    .then((results) => console.log(results));

Output:

Code
[
  { status: 'fulfilled', value: 'Task 1 done' },
  { status: 'rejected', reason: 'Task 2 failed' },
  { status: 'fulfilled', value: 'Task 3 done' }
]

13. Combining Parallel and Sequential Promises

Run some in parallel, then process results sequentially.

JavaScript
Promise.all([
    new Promise((resolve) => setTimeout(() => resolve("Task A done"), 1000)),
    new Promise((resolve) => setTimeout(() => resolve("Task B done"), 500))
])
    .then(([resultA, resultB]) => {
        console.log(resultA, resultB);
        return new Promise((resolve) => setTimeout(() => resolve("Final Task done"), 700));
    })
    .then((finalResult) => console.log(finalResult));

Output:

Code
Task A done Task B done
Final Task done

14. Wrapping Callbacks into Promises

Convert callback-based functions into promises for easier handling.

JavaScript
function loadData(callback) {
    setTimeout(() => callback("Data loaded"), 1000);
}

function promisifiedLoadData() {
    return new Promise((resolve) => {
        loadData((result) => resolve(result));
    });
}

promisifiedLoadData().then((data) => console.log(data));

Output:

Code
Data loaded

Benefits of Promises

Summary

JavaScript Promises simplify the handling of asynchronous operations like API calls, timeouts, and file loading. With states like pending, fulfilled, and rejected, they provide structured ways to manage results. Methods like Promise.all(), Promise.any(), Promise.race(), and Promise.allSettled() make it easier to control complex asynchronous flows. By offering features such as chaining, error handling, and integration with async/await, Promises have become an essential tool for modern JavaScript development.