Promises and Async/Await Explained
Key Concepts
- Promises
- Async/Await
- Chaining Promises
- Error Handling with Promises
- Error Handling with Async/Await
- Parallel Execution
Promises
Promises are objects that represent the eventual completion (or failure) of an asynchronous operation and its resulting value. A Promise can be in one of three states: pending, fulfilled, or rejected.
Example:
let promise = new Promise((resolve, reject) => { setTimeout(() => resolve("Done!"), 1000); }); promise.then(result => console.log(result)); // Outputs: Done!
Analogies: Think of a Promise as a ticket for a movie. You get the ticket now, but the movie starts later.
Async/Await
Async/Await is syntactic sugar built on top of Promises, making asynchronous code easier to write and read. The async
keyword is used to define an asynchronous function, and await
is used to pause the execution of the function until the Promise is resolved.
Example:
async function fetchData() { let promise = new Promise((resolve, reject) => { setTimeout(() => resolve("Data fetched!"), 1000); }); let result = await promise; console.log(result); // Outputs: Data fetched! } fetchData();
Analogies: Async/Await is like having a VIP pass that lets you skip the line and go straight in.
Chaining Promises
Chaining Promises allows you to perform a series of asynchronous operations in sequence. Each then
call returns a new Promise, which allows for further chaining.
Example:
let promise = new Promise((resolve, reject) => { setTimeout(() => resolve(1), 1000); }); promise .then(result => { console.log(result); // Outputs: 1 return result * 2; }) .then(result => { console.log(result); // Outputs: 2 return result * 2; }) .then(result => { console.log(result); // Outputs: 4 });
Analogies: Chaining Promises is like a relay race where each runner passes the baton to the next.
Error Handling with Promises
Error handling in Promises is done using the catch
method, which is called when a Promise is rejected. It allows you to handle errors gracefully.
Example:
let promise = new Promise((resolve, reject) => { setTimeout(() => reject("Error!"), 1000); }); promise .then(result => console.log(result)) .catch(error => console.error(error)); // Outputs: Error!
Analogies: Think of catch
as a safety net that catches the performer if they fall.
Error Handling with Async/Await
Error handling in Async/Await is done using try/catch
blocks. The try
block contains the asynchronous code, and the catch
block handles any errors that occur.
Example:
async function fetchData() { try { let promise = new Promise((resolve, reject) => { setTimeout(() => reject("Error!"), 1000); }); let result = await promise; console.log(result); } catch (error) { console.error(error); // Outputs: Error! } } fetchData();
Analogies: The try/catch
block is like a safety net in a circus act.
Parallel Execution
Parallel execution allows multiple asynchronous operations to run concurrently. The Promise.all
method is used to run multiple Promises in parallel and wait for all of them to complete.
Example:
let promise1 = new Promise((resolve, reject) => { setTimeout(() => resolve("First"), 1000); }); let promise2 = new Promise((resolve, reject) => { setTimeout(() => resolve("Second"), 1000); }); Promise.all([promise1, promise2]) .then(results => console.log(results)); // Outputs: ["First", "Second"]
Analogies: Parallel execution is like having multiple performers doing their acts simultaneously on stage.