Understanding Callbacks, Promises and Async/Await: Evolution and Best Practices
In the world of JavaScript, asynchronous programming is essential for handling tasks like fetching data from APIs. Over the years, JavaScript has evolved to make asynchronous code more manageable by introducing callbacks, promises, and async/await. Each has its own pros, cons and specific use cases.
This blog will guide you on how they were introduced and when to use them.
A callback is simply a function passed as an argument to another function. Callbacks have been a part of JavaScript since its early days, long before promises or async/await were introduced. It gets executed after the completion of an asynchronous operation.
How It Works
function fetchData(callback) {
setTimeout(() => {
callback("Data fetched!");
}, 1000);
}
fetchData((result) => {
console.log(result);
});
Pros:
Use callbacks when the operation is simple and does not involve chaining multiple asynchronous tasks.
Cons:
Callback Hell: Nesting multiple callbacks leads to pyramid code which is hard to read.
Error Handling: Managing errors in callback based code is difficult.
Promises represent a value that may be available now or in the future or never. They have three states: pending, fulfilled, and rejected. Promises were introduced in ES6 to address the issues of callback hell and improve error handling.
How It Works
const fetchData = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Data fetched!");
}, 1000);
});
};
fetchData()
.then((result) => console.log(result))
.catch((error) => console.error(error));
Pros:
Chaining: Promises can be chained make the code more readable.
Error Handling: catch
allows centralized error handling.
Cons:
Still verbose compared to modern alternatives like async/await
.
What Is Async/Await?
async/await
is a syntactic sugar built on top of promises and introduced in ES2017. It allows asynchronous code to look and behave like synchronous code. Use async/await
for complex code where readability and maintainability are priorities.
How It Works
const fetchData = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Data fetched!");
}, 1000);
});
};
const getData = async () => {
try {
const result = await fetchData();
console.log(result);
} catch (error) {
console.error(error);
}
};
getData();
Pros
Readability: Code looks cleaner and is easier to understand.
Error Handling: Errors can be caught using try/catch
making debugging simpler.
Cons
Requires JavaScript version that supports ES2017+.
Callbacks:
Use when code is simple.
Example: Event listeners, basic operations.
Promises:
Use for tasks involving multiple asynchronous operations or when you need to chain tasks.
Example: Fetching data sequentially.
Async/Await:
Use when readability and maintainability are essential especially in complex workflows.
Example: API calls with multiple dependent steps.
The evolution from callbacks to promises and finally to async/await, demonstrates JavaScript is focusing on improving developer experience. While each has its place, async/await is often the preferred choice for modern applications due to its readability and maintainability. However, understanding all three is crucial for working with JavaScript as you will encounter them in different contexts.
Follow me for more blogs.
Join Sanjoy on Peerlist!
Join amazing folks like Sanjoy and thousands of other people in tech.
Create ProfileJoin with Sanjoy’s personal invite link.
0
5
0