JavaScript is single-threaded, but the browser/node environment performs background tasks.
Callbacks, promises and async/await let us manage those background operations (network, timers, file access, etc.) without blocking execution.
Callbacks — old but still used
Promises — foundation of modern async JS
async/await — modern recommended syntax
A Promise is an object that represents the eventual completion (or failure) of an asynchronous operation and its resulting value.
Pending: Initial state, neither fulfilled nor rejected
Fulfilled: Operation completed successfully
Rejected: Operation failed
const myPromise = new Promise((resolve, reject) => {
// Asynchronous operation
const success = true;
if (success) {
resolve("Operation completed successfully!");
} else {
reject("Operation failed!");
}
});
// Using .then() and .catch()
myPromise
.then(result => {
console.log(result); // "Operation completed successfully!"
})
.catch(error => {
console.error(error); // "Operation failed!"
})
.finally(() => {
console.log("This runs regardless of success/failure");
});
// Promise.all() - Waits for all promises to resolve
Promise.all([promise1, promise2, promise3])
.then(results => {
console.log(results); // Array of all results
})
.catch(error => {
// Fails if any promise rejects
});
// Promise.race() - Returns first settled promise
Promise.race([promise1, promise2])
.then(firstResult => {
console.log(firstResult);
});
// Promise.allSettled() - Waits for all to settle (resolve or reject)
Promise.allSettled([promise1, promise2])
.then(results => {
results.forEach(result => {
if (result.status === 'fulfilled') {
console.log('Value:', result.value);
} else {
console.log('Reason:', result.reason);
}
});
});
Async/await is syntactic sugar built on top of promises that makes asynchronous code easier to write and read.
The async keyword makes a function return a promise
async function fetchData() {
return "Data fetched!";
}
async function getUserData() {
try {
const user = await fetchUser();
const posts = await fetchUserPosts(user.id);
const comments = await fetchUserComments(user.id);
return { user, posts, comments };
} catch (error) {
console.error("Error fetching data:", error);
throw error; // Re-throw the error
}
}
async function fetchUserData(userId, retries = 3) {
try {
const response = await fetch(`https://api.example.com/users/${userId}`);
if (!response.ok) {
throw new Error('Network response was not ok');
}
const user = await response.json();
console.log('User data:', user);
return user;
} catch (error) {
if (retries > 0) {
console.log(`Retrying... ${retries} attempts left`);
return fetchWithRetry(userId, retries - 1);
} else {
throw new Error(`Failed after multiple attempts: ${error.message}`);
}
}
}