Callbacks vs Promises vs Async/Await
Callbacks, Promises, and Async/Await are three different approaches in JavaScript for handling asynchronous operations. Let’s briefly discuss each.
Callback
Callbacks are functions passed as arguments to other functions, and they are executed after the completion of a specific task. Callbacks have been a traditional way of handling asynchronous operations in JavaScript.
Note: Callbacks can lead to “callback hell” or “pyramid of doom” when dealing with multiple nested asynchronous operations, making the code harder to read and maintain.
Example: fetchUserDataWithCallback
simulates fetching user data from an API and then invokes a callback (processUserData
) to process the data.
Javascript
// Callback function to process user data function processUserData(data, callback) { console.log( "Processing user data:" , data); callback(); } // Function to fetch user data with a callback function fetchUserDataWithCallback(callback) { // Simulating an API request const userData = { id: 1, name: "John Doe" }; callback(userData); } // Using the callback fetchUserDataWithCallback((data) => { processUserData(data, () => { console.log( "User data processed successfully." ); }); }); |
Processing user data: { id: 1, name: 'John Doe' } User data processed successfully.
Promises
Promises were introduced to address the callback hell issue and provide a more structured way of handling asynchronous code. A Promise is an object representing the eventual completion or failure of an asynchronous operation.
Promises provide a more structured way to handle asynchronous code and simplify error handling. They can be chained using .then()
and .catch()
.
Example: Here, fetchUserDataWithPromise
returns a Promise, simulating the asynchronous nature of an API request. The .then()
method handles the resolved value, and the .catch()
method handles errors.
Javascript
// Function to fetch user data with a Promise function fetchUserDataWithPromise() { // Simulating an API request const userData = { id: 1, name: "John Doe" }; return new Promise((resolve, reject) => { if (userData) { resolve(userData); } else { reject( "Error fetching user data." ); } }); } // Using the Promise fetchUserDataWithPromise() .then((data) => { console.log( "Processing user data:" , data); console.log( "User data processed successfully." ); }) . catch ((error) => { console.error( "Error:" , error); }); |
Processing user data: { id: 1, name: 'John Doe' } User data processed successfully.
Async/Await
Async/Await is a syntactic sugar built on top of Promises. It allows writing asynchronous code that looks and behaves more like synchronous code, making it easier to read and understand.
Async/Await simplifies asynchronous code by allowing the use of the await
keyword to pause the execution until the Promise is resolved. It’s particularly useful when dealing with multiple asynchronous operations.
Example: Here, fetchUserDataWithAsyncAwait
returns a Promise, and processUserDataWithAsyncAwait
is an asynchronous function that uses the await
keyword to handle the resolved value.
Javascript
// Function to fetch user data with Async/Await async function fetchUserDataWithAsyncAwait() { // Simulating an API request const userData = { id: 1, name: "John Doe" }; return new Promise((resolve) => { resolve(userData); }); } // Function to process user data using Async/Await async function processUserDataWithAsyncAwait() { try { const data = await fetchUserDataWithAsyncAwait(); console.log( "Processing user data:" , data); console.log( "User data processed successfully." ); } catch (error) { console.error( "Error:" , error); } } // Using Async/Await processUserDataWithAsyncAwait(); |
Processing user data: { id: 1, name: 'John Doe' } User data processed successfully.
Differences between Callbacks, Promises, and Async/Await:
Parameter |
Callbacks |
Promises |
Async/Await |
---|---|---|---|
Main focus |
Manage asynchronous |
Deliver a more robust explanation for managing asynchronous operations |
Make asynchronous code appears synchronous improve code quality |
Complexity |
Less readable because of nesting or callback hell |
More readable as compare to Callbacks |
Highly readable with clean code. |
Syntax |
Function-based structure |
Introduced the Promise object and methods like .then() and .catch() |
Async and Await used |
Use case |
Suitable for simple cases |
Perfect for complex asynchronous operations, managing multiple asynchronous and handle API calls |
Use to maintain code in large applications improves the code quality. |
Performance |
Normally good in performance |
Just overhead due to the promise creation |
slight overhead as Comparable to promises |
Debugging complexity |
difficult to debug |
Easier to debugging |
Streamlines debugging by letting step through debugging similar to synchronous |
Browser and Environment |
JavaScript environments |
Modern web browsers and Node.js |
Modern web browsers and Node.js |
Way of Error Handling |
error handling separately |
error handling with .catch() method |
error handling using try and catch blocks |
Similarity between Callbacks, Promises, and Async/Await:
- Callbacks, Promises, and Async/Await they all are used to handle asynchronous operations in JavaScript. All these three are designed to handle the results of asynchronous operations. i.e. similarities in asynchronous operations and handling of asynchronous results.
- They all handle errors in their own way, Callbacks use the error first convention, Promises uses the .catch() method, and Async/Await uses try and catch block.
- Callbacks, Promises, and Async/Await they all operate on the JavaScript event loop. i.e. similarity in event loop utilization.
- They all Callbacks, Promises, and Async/Await they all enable the execution of non-blocking code. This means JavaScript engines can execute other tasks/operations while waiting for an asynchronous operation to complete, they are similar in nature to Non-blocking code execution.
Contact Us