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:
Pending – The task is still in progress and has not yet finished.
Fulfilled – The task completed successfully, and a result is available.
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
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
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.
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:
Task 3 failed
2. Promise.allSettled()
Runs all promises and returns results for both fulfilled and rejected ones.
Promise.allSettled([
Promise.resolve("Task 1 done"),
Promise.reject("Task 2 failed"),
Promise.resolve("Task 3 done")
])
.then((results) => console.log(results));
Output:
[
{ 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).
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:
Task 2 finished
4. Promise.any()
Resolves as soon as the first promise is fulfilled. Rejects only if all fail.
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:
Task 2 done
5. Promise.resolve()
Creates a promise that resolves immediately with a given value.
Promise.resolve("Immediate success")
.then((value) => console.log(value));
Output:
Immediate success
6. Promise.reject()
Creates a promise that rejects immediately.
Promise.reject("Immediate failure")
.catch((error) => console.error(error));
Output:
Immediate failure
7. Promise.finally()
Runs cleanup code after a promise settles, regardless of success or failure.
Promise.resolve("Task completed")
.then((result) => console.log(result))
.catch((error) => console.error(error))
.finally(() => console.log("Cleanup completed"));
Output:
Task completed
Cleanup completed
8. Promise Chaining with .then()
Allows sequential operations.
Promise.resolve(5)
.then((value) => value * 2) // 10
.then((value) => value + 3) // 13
.then((finalValue) => console.log(finalValue));
Output:
13
9. Sequential Execution with reduce()
Using .reduce()
to process tasks in sequence.
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:
Processing task 1
Processing task 2
Processing task 3
10. Dynamic Promise Creation
Creating promises based on runtime conditions.
function asyncTask(taskName) {
return new Promise((resolve) => {
setTimeout(() => resolve(`${taskName} completed`), 1000);
});
}
asyncTask("Download File")
.then((result) => console.log(result));
Output:
Download File completed
11. Timeout Handling with Promise.race()
Set a timeout limit for an async task.
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:
Timeout!
12. Handling Multiple Failures with Promise.allSettled()
Useful when you need to see results of all tasks, even failed ones.
Promise.allSettled([
Promise.resolve("Task 1 done"),
Promise.reject("Task 2 failed"),
Promise.resolve("Task 3 done")
])
.then((results) => console.log(results));
Output:
[
{ 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.
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:
Task A done Task B done
Final Task done
14. Wrapping Callbacks into Promises
Convert callback-based functions into promises for easier handling.
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:
Data loaded
Benefits of Promises
Avoid Callback Hell – Promises keep asynchronous code cleaner and easier to read.
Better Error Handling – Errors can be managed in one place using .catch()
.
Chaining Support – Multiple async operations can run in sequence with .then()
.
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.