How do you handle errors in asynchronous operations?
TL;DR
Handle promise rejections with try...catch around await or with .catch() on a promise chain. Remember that Fetch fulfills its promise for HTTP errors such as 404 and 500, so check response.ok and throw an application error yourself.
async function fetchData() {try {// This request will fail (example domain)const response = await fetch('https://api.example.com/data');if (!response.ok) throw new Error(`HTTP ${response.status}`);const data = await response.json();console.log(data);} catch (error) {console.error('Error fetching data:', error);}}fetchData(); // Error fetching data: ....
With Promises, you can use the .catch() method:
fetch('https://api.example.com/data') // This request will fail (example domain).then((response) => {if (!response.ok) throw new Error(`HTTP ${response.status}`);return response.json();}).then((data) => console.log(data)).catch((error) => console.error('Error fetching data:', error));
Match the error channel
Error handling must follow the abstraction that reports completion: promise rejections and callback error arguments travel through different channels.
A try...catch around code that merely starts callback-based work cannot catch an error thrown later by that callback.
Using try...catch with async/await
Basic usage
When using async/await, you can handle errors by wrapping your asynchronous code in a try...catch block. This allows you to catch any errors that occur during the execution of the await statement.
async function fetchData() {try {// This request will fail (example domain)const response = await fetch('https://api.example.com/data');if (!response.ok) throw new Error(`HTTP ${response.status}`);const data = await response.json();console.log(data);} catch (error) {console.error('Error fetching data:', error);}}fetchData(); // Error fetching data: ....
Nested asynchronous operations
If you have multiple asynchronous operations, you can nest try...catch blocks to handle errors at different levels.
async function fetchUser() {// Simulate a successful async operationreturn { id: 1, name: 'Alice' };}async function fetchUserPosts() {// Simulate a failed async operationthrow new Error('Failed to fetch posts');}async function loadUserData() {try {const user = await fetchUser();console.log('User:', user);try {const posts = await fetchUserPosts();console.log('Posts:', posts);} catch (postsError) {console.error('Error fetching posts:', postsError.message);}} catch (userError) {console.error('Error fetching user:', userError.message);}}loadUserData();
Using .catch() with Promises
Basic usage
When working with Promises, you can handle errors using the .catch() method. This method is called if the Promise is rejected.
fetch('https://api.example.com/data').then((response) => {if (!response.ok) throw new Error(`HTTP ${response.status}`);return response.json();}).then((data) => console.log(data)).catch((error) => console.error('Error fetching data:', error));
Chaining multiple Promises
If you have multiple Promises chained together, you can use a single .catch() at the end to handle any errors that occur in any of the Promises.
fetch('https://api.example.com/data').then((response) => {if (!response.ok) throw new Error(`HTTP ${response.status}`);return response.json();}).then((data) => {// Process datareturn processData(data);}).then((result) => {// Further processingconsole.log(result);}).catch((error) => console.error('Error in the chain:', error));