Async¶
Rule¶
Use async/await keyword instead of chaining promises
- Readability - async/await makes asynchronous code look and behave more like synchronous code, which is easier to understand at a glance.
- Error handling - With async/await, you can use familiar try/catch blocks instead of attaching .catch() handlers, making error handling more intuitive.
- Debugging - Stack traces are more meaningful with async/await, making it easier to locate errors.
- Control flow - async/await makes complex control flows like conditional logic, loops, and variable scoping more straightforward.
- Avoiding callback hell - Deep promise chains can become difficult to read and maintain, similar to callback hell.
- Intermediate values - You can access intermediate results from previous async operations without nesting.
https://www.youtube.com/watch?v=Pz2cL01bmwQ&t=629s
Examples¶
🚨 DON’T¶
// Complex promise chaining
const handleData = () => {
fetchData()
.then((data) => processData(data))
.then((result) => displayResult(result))
.catch((error) => handleError(error));
};
// Nested promise chains (callback hell 2.0)
const processUserData = (userId) => {
return getUserById(userId).then((user) => {
return getProfilePicture(user.profileId).then((picture) => {
return getUserPreferences(user.id).then((preferences) => {
return {
user,
picture,
preferences,
};
});
});
});
};
// Conditional logic with promises
const processData = (shouldCompress) => {
return fetchData().then((data) => {
if (shouldCompress) {
return compressData(data).then((compressed) => saveData(compressed));
} else {
return saveData(data);
}
});
};
// Mixed async patterns
const handleRequest = () => {
fetchUser().then(async (user) => {
const profile = await getProfile(user.id);
return processProfile(profile);
});
};
✅ DO¶
// Clean async/await syntax
const handleData = async () => {
try {
const data = await fetchData();
const result = await processData(data);
await displayResult(result);
} catch (error) {
handleError(error);
}
};
// Parallel execution for independent operations
const loadDashboard = async () => {
try {
const [user, notifications, settings] = await Promise.all([
getUser(),
getNotifications(),
getSettings(),
]);
return { user, notifications, settings };
} catch (error) {
console.error("Dashboard loading failed:", error);
throw error;
}
};
// Clear sequential flow with intermediate values
const processUserData = async (userId) => {
try {
const user = await getUserById(userId);
const picture = await getProfilePicture(user.profileId);
const preferences = await getUserPreferences(user.id);
return {
user,
picture,
preferences,
};
} catch (error) {
console.error("Failed to process user data:", error);
throw error;
}
};
// Simple conditional logic
const processData = async (shouldCompress) => {
try {
const data = await fetchData();
const finalData = shouldCompress ? await compressData(data) : data;
return saveData(finalData);
} catch (error) {
console.error("Data processing failed:", error);
throw error;
}
};
// Proper loop handling with parallel execution
const processItems = async (items) => {
try {
return Promise.all(items.map((item) => processItem(item)));
} catch (error) {
console.error("Item processing failed:", error);
throw error;
}
};