JavaScript Async/Await - Exercise 3
Promises let asynchronous operations progress concurrently, but true parallelism depends on the environment doing work at the same time behind the scenes. The surrounding async function resumes after the awaited Promise settles, so the result is available on the next line.
const userPromise = fetchUser();
const postsPromise = fetchPosts();
const [user, posts] = await Promise.all([userPromise, postsPromise]);Use for...of with await inside the loop when each async step should finish before the next one begins. The surrounding async function resumes after the awaited Promise settles, so the result is available on the next line.
for (const id of ids) {
const user = await fetchUser(id);
console.log(user.name);
}forEach() does not wait for async callbacks, so the outer function keeps running and errors are harder to coordinate. The surrounding async function resumes after the awaited Promise settles, so the result is available on the next line.
ids.forEach(async id => {
const user = await fetchUser(id);
console.log(user.name);
});
console.log('Loop finished scheduling callbacks');Mapping with an async callback returns an array of promises, which you can later await together with Promise.all(). The surrounding async function resumes after the awaited Promise settles, so the result is available on the next line.
const userPromises = ids.map(async id => {
return fetchUser(id);
});
const users = await Promise.all(userPromises);Placing await inside the loop makes each iteration pause until its async work finishes, so the loop runs sequentially instead of starting everything at once. Use this pattern when each iteration depends on the previous result or when order matters.
for (const file of files) {
await uploadFile(file);
console.log('Uploaded:', file.name);
}An async generator uses async function* and yield to produce values over time, which callers consume with for await...of. The surrounding async function resumes after the awaited Promise settles, so the result is available on the next line.
async function* counter() {
yield 1;
yield 2;
}
for await (const value of counter()) {
console.log(value);
}finally runs after success and failure, so it is the safest place to clear loading state and re-enable UI controls. The surrounding async function resumes after the awaited Promise settles, so the result is available on the next line.
setSaving(true);
try {
await saveSettings();
} finally {
setSaving(false);
}Catch the failure and return a safe default when the calling code can continue with fallback data. The surrounding async function resumes after the awaited Promise settles, so the result is available on the next line.
async function loadTheme() {
try {
return await fetchTheme();
} catch {
return { color: 'blue' };
}
}Top-level await lets a module finish important asynchronous setup before the rest of the module graph continues. The surrounding async function resumes after the awaited Promise settles, so the result is available on the next line.
const config = await fetch('/config.json').then(response => response.json());
export default config;Pass a cancellation signal, such as an AbortSignal, and stop work or throw when that signal says the operation is no longer needed. The surrounding async function resumes after the awaited Promise settles, so the result is available on the next line.
const controller = new AbortController();
fetch('/api/report', { signal: controller.signal });
controller.abort();