JavaScript
Promises, Async/Await
Explore Promises, Async/Await, Promise.all, Promise.race, and proper error handling in asynchronous JavaScript.
Promises
A Promise is an object representing the eventual completion (or failure) of an asynchronous operation and its resulting value. It acts as a placeholder for a value that will be available in the future.
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Data received");
}, 1000);
});
myPromise
.then(data => console.log(data))
.catch(error => console.error(error));Callbacks vs Promises – Same Async Operation
Using Callbacks
function fetchUserCallback(callback) {
setTimeout(() => {
callback(null, { id: 1, name: "Alice" });
}, 1000);
}
function fetchPostsCallback(userId, callback) {
setTimeout(() => {
callback(null, ["Post 1", "Post 2"]);
}, 1000);
}
fetchUserCallback((err, user) => {
if (err) return console.error(err);
fetchPostsCallback(user.id, (err, posts) => {
if (err) return console.error(err);
console.log('User:', user);
console.log('Posts:', posts);
});
});Drawbacks:
- Nested callbacks → callback hell.
- Hard to read and maintain.
- Verbose error handling.
Using Promises
function fetchUser() {
return new Promise(resolve => {
setTimeout(() => resolve({ id: 1, name: "Alice" }), 1000);
});
}
function fetchPosts(userId) {
return new Promise(resolve => {
setTimeout(() => resolve(["Post 1", "Post 2"]), 1000);
});
}
fetchUser()
.then(user => {
console.log('User:', user);
return fetchPosts(user.id);
})
.then(posts => {
console.log('Posts:', posts);
})
.catch(err => console.error(err));Callback Hell Illustration
Callback Hell Example
setTimeout(() => {
console.log('Step 1 completed');
setTimeout(() => {
console.log('Step 2 completed');
setTimeout(() => {
console.log('Step 3 completed');
setTimeout(() => {
console.log('All steps completed');
}, 1000);
}, 1000);
}, 1000);
}, 1000);Problems:
- Deeply nested structure.
- Difficult to read and maintain.
- Hard to handle errors at each level.
Cleaner Solutions
Using Named Callback Functions
function step1(callback) {
setTimeout(() => {
console.log('Step 1 completed');
callback();
}, 1000);
}
function step2(callback) {
setTimeout(() => {
console.log('Step 2 completed');
callback();
}, 1000);
}
function step3(callback) {
setTimeout(() => {
console.log('Step 3 completed');
callback();
}, 1000);
}
function allSteps() {
step1(() => {
step2(() => {
step3(() => {
console.log('All steps completed');
});
});
});
}
allSteps();- Slightly cleaner, but still nested.
Using Promises
function step1() {
return new Promise(resolve => {
setTimeout(() => {
console.log('Step 1 completed');
resolve();
}, 1000);
});
}
function step2() {
return new Promise(resolve => {
setTimeout(() => {
console.log('Step 2 completed');
resolve();
}, 1000);
});
}
function step3() {
return new Promise(resolve => {
setTimeout(() => {
console.log('Step 3 completed');
resolve();
}, 1000);
});
}
step1()
.then(step2)
.then(step3)
.then(() => console.log('All steps completed'))
.catch(err => console.error(err));- Promises provide a flat, readable chain.
- Errors handled in one place.
Using Async/Await
async function runSteps() {
try {
await step1();
await step2();
await step3();
console.log('All steps completed');
} catch (err) {
console.error(err);
}
}
runSteps();- Most readable and easy to follow.
- Cleaner error handling.
- Looks synchronous but runs asynchronously.
Promise.all & Promise.race
Promise.all – Wait for multiple promises
Promise.all([fetchUser(), fetchPosts(1)])
.then(([user, posts]) => {
console.log('User:', user);
console.log('Posts:', posts);
});Promise.race – First settled promise wins
Promise.race([fetchUser(), fetchPosts(1)])
.then(first => {
console.log('First resolved:', first);
});Error Handling in Async Code
With Promises
myPromise
.then(data => console.log(data))
.catch(err => console.error("Error:", err));With Async/Await
async function fetchData() {
try {
const data = await myPromise;
console.log(data);
} catch (err) {
console.error("Error:", err);
}
}Async JS
JavaScript isn’t just about synchronous code — mastering asynchronous patterns is essential. Below is a complete guide covering Callbacks, Functional Arguments, Callback Hell, and the Event Loop.
Thenables
A deep dive into Thenables in JavaScript, how they work, and how they compare to Promises.