Why Async/Await is Better Than Using Axios or Fetch Directly
When working with APIs in JavaScript, dealing with asynchronous requests is crucial. There are different ways to handle these requests, the most popular being Axios, Fetch, and Async/Await. While Axios and Fetch are powerful tools for making HTTP requests, using them directly can sometimes lead to less maintainable and readable code. This is where async/await shines. In this blog, we'll explore why async/await is a better approach than using Axios or Fetch directly.
1. Improved Readability and Clean Code
When making API requests, maintaining clear and readable code is crucial. Without async/await, you typically rely on Promises, which can sometimes lead to complicated "promise chains" or deeply nested .then()
blocks, reducing the readability of your code.
Example Using Fetch:
fetch(url)
.then(response => response.json())
.then(data => {
console.log(data);
})
.catch(error => {
console.error('Error:', error);
});
Example Using Axios:
axios.get(url)
.then(response => {
console.log(response.data);
})
.catch(error => {
console.error('Error:', error);
});
Both Fetch and Axios use .then() and .catch() to handle responses and errors. While this works fine for simple requests, it can become cumbersome for more complex workflows.
Example Using Async/Await:
try {
const response = await fetch(url);
const data = await response.json();
console.log(data);
} catch (error) {
console.error('Error:', error);
}
Async/await eliminates the need for chaining .then()
calls. The code is linear and synchronous in appearance, making it easier to follow, especially for developers who may be less familiar with JavaScript's asynchronous nature.
2. Error Handling Made Easy
Another significant advantage of async/await is its superior error handling. With Promises (used in Axios and Fetch), handling errors can be tricky, especially when you have multiple .then()
blocks. If an error occurs, you have to ensure it is caught in the .catch()
block.
With async/await, you can handle errors using try/catch blocks, which are familiar to anyone who's worked with synchronous code in JavaScript.
Example Using Axios and .catch()
:
axios.get(url)
.then(response => {
console.log(response.data);
})
.catch(error => {
console.error('Error:', error);
});
Example Using Async/Await:
try {
const response = await axios.get(url);
console.log(response.data);
} catch (error) {
console.error('Error:', error);
}
In this case, async/await with try/catch creates a much cleaner and more predictable flow, making it easier to spot where the error handling occurs. This results in fewer potential bugs and more manageable code.
3. Sequential and Parallel Execution
With async/await, you can control the flow of your asynchronous requests, either running them sequentially or in parallel, depending on the situation.
Example: Sequential Requests
If you need to make a series of API requests one after the other, async/await ensures that each request finishes before moving to the next one.
async function fetchSequential() {
const response1 = await fetch(url1);
const data1 = await response1.json();
const response2 = await fetch(url2);
const data2 = await response2.json();
return { data1, data2 };
}
This code runs the two requests sequentially, making sure the second request happens only after the first one completes.
Example: Parallel Requests
On the other hand, if you want to make multiple requests in parallel (to speed things up), you can use Promise.all()
with async/await:
async function fetchParallel() {
const [response1, response2] = await Promise.all([
fetch(url1),
fetch(url2)
]);
const data1 = await response1.json();
const data2 = await response2.json();
return { data1, data2 };
}
With async/await, it's much easier to manage both sequential and parallel requests.
4. Compatibility and Consistency
Another benefit of async/await is its universal compatibility with both Fetch and Axios. While Axios provides additional features such as automatic JSON conversion, request interceptors, and timeouts, async/await remains a universal pattern that can work with any Promise-based library.
Axios: Works great with async/await, allowing you to combine Axios' features with the clean structure of async/await.
Fetch: Also works seamlessly with async/await, helping you avoid promise chains.
You don't have to choose between Axios or Fetch; you can choose the library that fits your needs and still benefit from the clean structure of async/await.
5. Advanced Features with Less Code
Async/await makes complex use cases easier to handle without extra libraries or complex configurations. For example, retry logic or conditional execution of asynchronous tasks can be implemented with fewer lines of code.
Example: Retry Logic with Async/Await:
async function fetchDataWithRetry(url, retries = 3) {
try {
const response = await fetch(url);
return await response.json();
} catch (error) {
if (retries === 0) throw error;
return fetchDataWithRetry(url, retries - 1);
}
}
This retry pattern is simple to implement using async/await, and it avoids the complexity of managing nested promises.
Conclusion
While Axios and Fetch are great libraries for making HTTP requests, using async/await offers a cleaner and more readable way to handle asynchronous code. By making the code look more like synchronous code, async/await improves readability, simplifies error handling, and allows better control over execution flow.
Ultimately, async/await is a modern JavaScript feature that allows for writing less code with fewer bugs and provides more maintainable codebases. Whether you're using Axios or Fetch, adopting async/await can enhance your development experience.
Subscribe to my newsletter
Read articles from Anish Agrawal directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by