In JavaScript, promises are used to handle asynchronous operations. A promise is an object that represents the eventual completion (or failure) of an asynchronous operation and its resulting value. Promises make asynchronous code easier to write and manage by avoiding "callback hell" and providing a cleaner syntax. In this article, we will cover how to create and handle promises in JavaScript with examples.
A promise in JavaScript is an object that may not have a value yet but will be resolved with a value at some point in the future. A promise has three states:
Here's a simple diagram:
To create a promise, you use the new Promise
constructor. The constructor takes a function (called the executor function) that has two parameters: resolve
and reject
.
let promise = new Promise(function(resolve, reject) { let success = true; // Change this to false to test rejection if (success) { resolve("Operation was successful!"); } else { reject("Operation failed."); } });
In this example, the promise is resolved if the success
variable is true, or rejected if it's false. The resolve()
function is called when the operation is successful, while the reject()
function is used when the operation fails.
Once a promise is created, you handle its resolution or rejection using the .then()
and .catch()
methods.
let promise = new Promise(function(resolve, reject) { let success = true; if (success) { resolve("Operation was successful!"); } else { reject("Operation failed."); } }); promise.then(function(result) { console.log(result); // Will log: Operation was successful! }).catch(function(error) { console.log(error); // Will log: Operation failed. });
In this example, if the promise is resolved, the .then()
method will handle the result. If the promise is rejected, the .catch()
method will handle the error.
Here’s an example of a promise that simulates an asynchronous task using setTimeout()
:
function fetchData() { return new Promise(function(resolve, reject) { setTimeout(function() { let success = true; // Simulate success or failure of fetching data if (success) { resolve("Data fetched successfully!"); } else { reject("Failed to fetch data."); } }, 2000); // Simulate a 2-second delay }); } fetchData() .then(function(result) { console.log(result); // Output: Data fetched successfully! }) .catch(function(error) { console.log(error); // Output: Failed to fetch data. });
In this example, the fetchData
function returns a promise. The promise is resolved or rejected after a 2-second delay, simulating an asynchronous operation like an API call.
Promises can be chained to perform multiple asynchronous tasks sequentially. Each .then()
method returns a new promise, allowing you to chain multiple operations in a cleaner and more readable way.
function firstTask() { return new Promise(function(resolve) { setTimeout(function() { console.log("First task completed."); resolve(); }, 1000); }); } function secondTask() { return new Promise(function(resolve) { setTimeout(function() { console.log("Second task completed."); resolve(); }, 1000); }); } function thirdTask() { return new Promise(function(resolve) { setTimeout(function() { console.log("Third task completed."); resolve(); }, 1000); }); } firstTask() .then(secondTask) .then(thirdTask) .then(function() { console.log("All tasks completed."); });
In this example, each task is executed sequentially. The firstTask
promise must resolve before the secondTask
promise is executed, and so on. The final .then()
logs when all tasks have completed.
Promise.all()
If you need to execute multiple asynchronous operations concurrently and wait for all of them to complete, you can use Promise.all()
. This method takes an array of promises and returns a new promise that resolves when all the promises in the array resolve.
function task1() { return new Promise(function(resolve) { setTimeout(function() { console.log("Task 1 completed."); resolve("Task 1 result"); }, 1000); }); } function task2() { return new Promise(function(resolve) { setTimeout(function() { console.log("Task 2 completed."); resolve("Task 2 result"); }, 1500); }); } function task3() { return new Promise(function(resolve) { setTimeout(function() { console.log("Task 3 completed."); resolve("Task 3 result"); }, 500); }); } Promise.all([task1(), task2(), task3()]) .then(function(results) { console.log("All tasks completed:", results); }) .catch(function(error) { console.log("Error:", error); });
In this example, all three tasks are executed concurrently. Promise.all()
waits for all promises to resolve and then returns an array of results. If any of the promises are rejected, the .catch()
method will handle the error.
Promise.race()
Unlike Promise.all()
, which waits for all promises to resolve, Promise.race()
returns the result of the first promise that resolves or rejects. This can be useful when you need to respond to the first task to complete.
function task1() { return new Promise(function(resolve) { setTimeout(function() { console.log("Task 1 completed."); resolve("Task 1 result"); }, 1000); }); } function task2() { return new Promise(function(resolve) { setTimeout(function() { console.log("Task 2 completed."); resolve("Task 2 result"); }, 1500); }); } Promise.race([task1(), task2()]) .then(function(result) { console.log("First task to complete:", result); }) .catch(function(error) { console.log("Error:", error); });
In this example, Promise.race()
will log the result of task1
because it completes first, even though task2
is still running.
Promises in JavaScript provide a powerful way to handle asynchronous operations in a more readable and maintainable manner. By using methods like .then()
, .catch()
, and Promise.all()
, you can manage multiple asynchronous operations efficiently. Understanding how to create and handle promises is crucial for writing modern JavaScript applications, especially when working with APIs, timers, or any asynchronous process.