Introduction
In the world of JavaScript, dealing with asynchronous operations is a daily task. Whether you're making API calls, setting timers, or handling file I/O, understanding how to manage these operations is crucial. In this blog post, we'll dive into two fundamental concepts for handling asynchronous tasks in JavaScript: Promises and async/await.
1. Understanding Asynchronous Programming
Before we delve into Promises and async/await, let's briefly discuss asynchronous programming. In a synchronous program, tasks are executed one after another, and each task must complete before the next one begins. This can lead to issues like blocking, where a time-consuming task can halt the execution of subsequent tasks.
For instance, let's assume there is a for loop running to calculate the sum from 1 to 100,000. This for loop will run synchronously, meaning it will do 1 + 2 = 3, then 3 + 3 = 6, then 6 + 4 = 10, and so on, one after another until it reaches the final sum. If we hypothetically assume that every addition operation takes 1 second, the total time taken will be 100,000 seconds.
Asynchronous programming allows multiple tasks to run independently, improving efficiency and responsiveness. Common scenarios requiring asynchronous operations include API calls, timers, and reading files.
For instance, if we want to make the above synchronous example asynchronous, we could split the task into two separate loops running simultaneously: one from 1 to 50,000 and another from 50,001 to 100,000, and then add the results of these two loops later. Hypothetically, if each operation still takes 1 second, the time taken to complete the task now becomes approximately 50,000 seconds, which is half of the previous time.
2. Promises in JavaScript
a. What is a Promise?
A Promise is an object representing the eventual completion or failure of an asynchronous operation. It has three states:
Pending: Initial state, neither fulfilled nor rejected.
Fulfilled: The operation completed successfully.
Rejected: The operation failed.
b. Creating a Promise
Creating a Promise involves defining its executor function (basically the task that we are trying to do asynchronously), which takes two arguments: resolve
and reject
. Here's a basic example:
const myPromise = new Promise((resolve, reject) => {
// here we can do the work asynchronously
let success = true; // if the function gets executed successfully
if (success) {
resolve("The operation was successful!"); // then we call resolve
} else {
reject("The operation failed."); // else we call reject
}
});
c. Consuming Promises
To handle the result of a Promise, you use the .then()
, .catch()
, and .finally()
methods.
myPromise
.then(result => {
console.log(result); // this will execute if the function executes successfully
// and the `result` is whatever we pass in the resolve() function
})
.catch(error => {
console.log(error); // this will execute if the function executes successfully
// and the `error` is whatever we pass in the reject() function
})
.finally(() => {
console.log("Promise has been settled."); // this runs regardless of whether
// the function was resolved or rejected
});
d. Simple API call using Promises
fetch('https://api.example.com/data') // The fetch function returns a promise
// that resolves to the Response object
// representing the response to the request.
.then(response => response.json())
.then(data => {
console.log(data); // whatever we want to do with the data
})
.catch(error => {
console.error('Error:', error); // whatever we want to do when an error occurs.
});
e. Handling multiple promises
JavaScript's Promise API provides two methods for dealing with multiple promises:
Promise.all
This method is used to run multiple promises in parallel and wait for all of them to resolve or for any of them to reject. If we are doing multiple API calls and we need the result of all the API calls to move forward we can use this method.
const promise1 = fetch('https://api.example.com/data1'); const promise2 = fetch('https://api.example.com/data2'); Promise.all([promise1, promise2]) .then(responses => Promise.all(responses.map(response => response.json()))) // this will only run after all the promises are resolved. .then(data => { console.log(data); }) .catch(error => { console.error('Error:', error); });
Promise.race
This method is used to run multiple promises in parallel and wait for the first one to settle (either resolve or reject). This method is useful when you only care about the fastest result or the first to settle.\
const promise1 = new Promise((resolve) => setTimeout(resolve, 100, 'First')); const promise2 = new Promise((resolve) => setTimeout(resolve, 200, 'Second')); Promise.race([promise1, promise2]) .then(result => { // this code block runs whenever one of the promise gets resolved. console.log(result); // 'First' }) .catch(error => { // this code block runs whenever one of the promise gets rejected. console.error('The first promise rejected:', error); });
3. async/await: A Syntactic Sugar for Promises
a. What is async/await?
async/await
is syntactic sugar built on top of Promises, making asynchronous code look and behave more like synchronous code. This improves readability and maintainability. We use try/catch block for error handling in async/await
b. Using async/await
An async
function returns a Promise. Within this function, the await
keyword can be used to pause the execution until the Promise resolves.
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data'); // execution will not proceed funther until the promise resolves
const data = await response.json();
console.log(data);
} catch (error) {
console.error('Error:', error);
}
}
fetchData();
Conclusion
Mastering Promises and async/await is essential for handling asynchronous operations in JavaScript. These tools not only improve the efficiency of your code but also make it more readable and maintainable. Keep experimenting with these concepts to become proficient in managing asynchronous tasks.
Further Reading and Resources
https://www.freecodecamp.org/news/what-is-promise-in-javascript-for-beginners/
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
Connect with me on LinkedIn to stay updated on my latest projects and insights, or visit my Portfolio website to learn more about my work and expertise.
Thank you for coming along on this adventure of learning Promises and Async/Await. I trust you discovered this guide to be useful and enlightening.
Happy coding! ๐