JavaScript Async Programming
Asynchronous programming is essential in JavaScript for handling operations like API calls, file I/O, and timers without blocking the main thread.
Promises
// Creating a promise
const promise = new Promise((resolve, reject) => {
const success = true;
if (success) {
resolve('Operation successful');
} else {
reject('Operation failed');
}
});
// Consuming promises
promise
.then(result => {
console.log(result); // 'Operation successful'
return 'Next value';
})
.then(result => {
console.log(result); // 'Next value'
})
.catch(error => {
console.error(error);
})
.finally(() => {
console.log('Always runs');
});
// Async operation
function fetchUser(id) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (id > 0) {
resolve({ id, name: 'John' });
} else {
reject('Invalid ID');
}
}, 1000);
});
}
fetchUser(1)
.then(user => console.log(user))
.catch(error => console.error(error));
// Promise.all - wait for all
const promise1 = fetch('/api/users');
const promise2 = fetch('/api/posts');
const promise3 = fetch('/api/comments');
Promise.all([promise1, promise2, promise3])
.then(([users, posts, comments]) => {
console.log('All data loaded');
})
.catch(error => {
console.error('One promise failed:', error);
});
// Promise.allSettled - wait for all, don't fail
Promise.allSettled([promise1, promise2, promise3])
.then(results => {
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(`Promise ${index} succeeded:`, result.value);
} else {
console.log(`Promise ${index} failed:`, result.reason);
}
});
});
// Promise.race - first to complete
Promise.race([promise1, promise2, promise3])
.then(result => {
console.log('First to finish:', result);
});
// Promise.any - first to succeed
Promise.any([promise1, promise2, promise3])
.then(result => {
console.log('First success:', result);
})
.catch(error => {
console.log('All failed:', error);
});Async/Await
// Basic async/await
async function getUser(id) {
const response = await fetch(`/api/users/${id}`);
const user = await response.json();
return user;
}
// Calling async function
getUser(1)
.then(user => console.log(user))
.catch(error => console.error(error));
// Or with async context
(async () => {
try {
const user = await getUser(1);
console.log(user);
} catch (error) {
console.error(error);
}
})();
// Error handling
async function fetchData() {
try {
const response = await fetch('/api/data');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error('Fetch failed:', error);
throw error; // Re-throw or handle
}
}
// Sequential vs Parallel
// Sequential (slower)
async function sequential() {
const user = await fetchUser(); // Wait 1s
const posts = await fetchPosts(); // Wait 1s
const comments = await fetchComments(); // Wait 1s
// Total: 3s
}
// Parallel (faster)
async function parallel() {
const [user, posts, comments] = await Promise.all([
fetchUser(),
fetchPosts(),
fetchComments()
]);
// Total: 1s (all run simultaneously)
}
// Top-level await (in modules)
const data = await fetch('/api/data');
const json = await data.json();
export default json;Callbacks vs Promises vs Async/Await
// Callback hell
getUser(1, (error, user) => {
if (error) return console.error(error);
getPosts(user.id, (error, posts) => {
if (error) return console.error(error);
getComments(posts[0].id, (error, comments) => {
if (error) return console.error(error);
console.log(comments);
});
});
});
// Promises - better
getUser(1)
.then(user => getPosts(user.id))
.then(posts => getComments(posts[0].id))
.then(comments => console.log(comments))
.catch(error => console.error(error));
// Async/await - best
async function loadData() {
try {
const user = await getUser(1);
const posts = await getPosts(user.id);
const comments = await getComments(posts[0].id);
console.log(comments);
} catch (error) {
console.error(error);
}
}Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free