Hey there! Let’s break down three important JavaScript methods for handling multiple asynchronous operations, especially when fetching data from APIs like the Fake Store API (https://fakestoreapi.com/products). We’ll use simple examples and see what the results look like.
1. Promise.all: Wait for All Success
Use Case: You want to fetch data from multiple sources, but you only want to proceed if all of them succeed. If any one fails, the whole thing stops.
Example: Fetch product data and user data (let’s pretend there’s a user endpoint) at the same time. We only want to continue if both requests are successful.
// Simulate fetching products and a single user (replace with actual user URL if needed)
// For simplicity, we'll use the products URL twice to demonstrate success.
const urls = [
'https://fakestoreapi.com/products',
'https://fakestoreapi.com/products' // Pretending this is a user URL
];
console.log("--- Promise.all Example ---");
Promise.all(urls.map(url => fetch(url)))
.then(responses => {
// Check if all responses are okay
if (!responses.every(response => response.ok)) {
throw new Error('One or more requests failed');
}
// Parse JSON for all successful responses
return Promise.all(responses.map(response => response.json()));
})
.then(dataArray => {
// dataArray is an array containing the results of each fetch in order
console.log("✅ Promise.all Success:");
console.log("First fetch result (Products):", dataArray[0].slice(0, 2)); // Show first 2 products
console.log("Second fetch result (Simulated User/Products):", dataArray[1].slice(0, 1)); // Show 1 item
})
.catch(error => {
console.error("❌ Promise.all Error:", error.message);
// This will catch network errors or our custom error if a response isn't ok
});
// --- Output (if both succeed) ---
// --- Promise.all Example ---
// ✅ Promise.all Success:
// First fetch result (Products): [
// {
// "id": 1,
// "title": "Fjallraven - Foldsack No. 1 Backpack, Fits 15 Laptops",
// "price": 109.95,
// ...
// },
// {
// "id": 2,
// "title": "Mens Casual Premium Slim Fit T-Shirts ",
// "price": 22.3,
// ...
// }
// ]
// Second fetch result (Simulated User/Products): [
// {
// "id": 1,
// "title": "Fjallraven - Foldsack No. 1 Backpack, Fits 15 Laptops",
// "price": 109.95,
// ...
// }
// ]
2. Promise.allSettled: Wait for All to Finish (Regardless of Outcome)
Use Case: You want to start multiple fetch requests and handle the results of each one individually, whether it succeeds or fails. You don’t want one failure to stop you from seeing the results of the others.
Example: Fetch products and also try to fetch from a URL that will fail (like a 404 Not Found page). We want to see the result of the product fetch even if the second one fails.
// Fetch products and a URL that will likely fail (simulate an error)
const urlsForSettled = [
'https://fakestoreapi.com/products',
'https://httpstat.us/404' // This URL returns a 404 error
];
console.log("\n--- Promise.allSettled Example ---");
Promise.allSettled(urlsForSettled.map(url => fetch(url)))
.then(results => {
console.log("✅ Promise.allSettled Finished. Checking results:");
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(`✅ Request ${index + 1} succeeded:`);
result.value.json().then(data => {
if (Array.isArray(data)) {
console.log(" Data (first 1 item):", data.slice(0, 1));
} else {
console.log(" Data:", data);
}
}).catch(err => console.log(" (Error parsing JSON for request", index+1, ")", err.message));
} else if (result.status === 'rejected') {
// Handle fetch errors (network issues)
console.error(`❌ Request ${index + 1} failed:`, result.reason.message);
}
});
});
// Note: .catch is less common here as allSettled rarely rejects itself,
// but network issues during the fetch might still propagate depending on how fetch is used.
// --- Output ---
// --- Promise.allSettled Example ---
// ✅ Promise.allSettled Finished. Checking results:
// ✅ Request 1 succeeded:
// Data (first 1 item): [ { id: 1, title: 'Fjallraven - Foldsack No. 1 Backpack, Fits 15 Laptops', ... } ]
// ❌ Request 2 failed: Bad Request
3. Promise.race: Get the First Result
Use Case: You only care about the first operation that finishes, whether it succeeds or fails. Useful for timeouts.
Example: Fetch products, but also set a timer. Whichever finishes first (the fetch or the timer) determines the outcome.
console.log("\n--- Promise.race Example ---");
// Function to create a delay promise
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
const fetchPromise = fetch('https://fakestoreapi.com/products');
const timeoutPromise = delay(5000).then(() => { throw new Error('Timeout!'); });
Promise.race([fetchPromise, timeoutPromise])
.then(response => {
// If fetchPromise wins the race and resolves
if (response.ok) { // Check if it's the fetch response and successful
return response.json();
} else {
throw new Error(`HTTP Error: ${response.status}`);
}
})
.then(products => {
console.log("✅ Promise.race Success (Fetch won):");
console.log("First product:", products[0].title);
})
.catch(error => {
// This catches errors from the fetch or the timeout
if (error.message === 'Timeout!') {
console.error("⏱️ Promise.race Result: Timeout occurred.");
} else {
console.error("❌ Promise.race Error (Fetch lost or failed):", error.message);
}
});
// --- Typical Output (assuming fetch is faster than 5 seconds) ---
// --- Promise.race Example ---
// ✅ Promise.race Success (Fetch won):
// First product: Fjallraven - Foldsack No. 1 Backpack, Fits 15 Laptops
// --- Output if timeout was faster (hypothetical scenario) ---
// ⏱️ Promise.race Result: Timeout occurred.
Summary
Promise.all: Use when you need all operations to succeed. Great for fetching related data simultaneously. Fails fast if any promise rejects.Promise.allSettled: Use when you want to handle the result of every operation, regardless of success or failure. No fast failure; waits for all to settle.Promise.race: Use when you only care about the first operation to complete. Perfect for implementing timeouts.