A brief info in way of handling Asynchronous in Js
Topics covered Promises and its methods, Async, Await, Web-API.
Introduction
In real-world JavaScript, we use async, await, and promises to deal with tasks that take time, like fetching data or handling user interactions. Promises help organize and make our code cleaner for these tasks. Async/await makes it even simpler, making the code look like it runs step by step, even though it's doing multiple things at once. It's like cooking a meal - you can start boiling water, chop veggies, and simmer sauce simultaneously, making the process faster and more efficient. In short, async and promises make our code handle multiple jobs smoothly, providing a better experience for users interacting with web applications.
Understanding Promises
Promises represent the eventual completion or failure of an asynchronous operation and its resulting value. They help streamline the flow of asynchronous code, making it more readable and maintainable.
Lets, code on Promises
function hero() {
return new Promise((resolve, reject) => {
if (100 % 2 == 0) {
resolve("Yay, We got it")
} else {
reject("Unfortunately, we didn't make it happen")
}
})
}
hero().then((data) => {
console.log(`data ${data}`)
})
.catch((error) => {
console.log(` error occured ${error}`)
})
// output - " data Yay, We got it"
// if it the statment(condition) provided is false,
// then output wiil be -
// " error occured Unfortunately, we didn't make it happen"
Let's break the code in simpler way.
The hero
function returns a promise that resolves with "Yay, We got it" if 100 is divisible by 2 (which is true), and rejects with "Unfortunately, we didn't make it happen" otherwise. When calling hero().then()
, the promise resolves, and the success callback prints "data Yay, We got it" to the console. If the statement were false, it would print "error occurred Unfortunately, we didn't make it happen" due to the catch
block capturing the rejection.
Let's get deeper into the promises methods.
Key Promise Methods
Promise.resolve
Promise.resolve returns a resolved promise with a given value. It's useful when you want to create a promise that is immediately resolved.
const resolvedPromise = Promise.resolve("Resolved value");
resolvedPromise.then(result => console.log(result)); // Output: Resolved value
Promise.reject
Promise.reject returns a rejected promise with a given reason. It's handy for creating a promise that is immediately rejected.
const rejectedPromise = Promise.reject("Error reason");
rejectedPromise.catch(error => console.error(error)); // Output: Error reason
Promise.all
Promise.all takes an array of promises and returns a single promise that resolves when all the promises in the array resolve. If any promise in the array is rejected, the entire Promise.all is rejected.
const promise1 = Promise.resolve("Promise 1");
const promise2 = Promise.resolve("Promise 2");
Promise.all([promise1, promise2])
.then(results => console.log(results)) // Output: ["Promise 1", "Promise 2"]
.catch(error => console.error(error));
// if error it only return on the error one
Promise.allSettled
Promise.allSettled is similar toPromise.all, but it waits for all promises to settle, whether resolved or rejected. It returns an array of objects representing the outcome of each promise.
const promise1 = Promise.resolve("Resolved Promise");
const promise2 = Promise.reject("Rejected Promise");
Promise.allSettled([promise1, promise2])
.then(results => console.log(results))
// Output: [{status: "fulfilled", value: "Resolved Promise"},
// {status: "rejected", reason: "Rejected Promise"}]
.catch(error => console.error(error));
Promise.any
Promise.any returns the first promise in an iterable that fulfills, not waiting for all promises to settle. If all promises are rejected, it returns an aggregate rejection.
const promise1 = Promise.reject("Promise 1 rejected");
const promise2 = Promise.resolve("Promise 2 resolved");
Promise.any([promise1, promise2])
.then(result => console.log(result)) // Output: Promise 2 resolved
.catch(errors => console.error(errors));
Promise.race
Promise.race returns a promise that fulfills or rejects as soon as one of the promises in an iterable fulfills or rejects.
const promise1 = new Promise(resolve => setTimeout(() => resolve("Promise 1"), 1000));
const promise2 = new Promise(resolve => setTimeout(() => resolve("Promise 2"), 500));
Promise.race([promise1, promise2])
.then(result => console.log(result)) // Output: Promise 2
.catch(error => console.error(error));
Now, Let's go to async
Async
In JavaScript, async
is a keyword used before a function declaration to indicate that the function will handle asynchronous operations. It allows the use of await
inside the function, making it possible to pause execution until a Promise is resolved.
Await
The await
keyword is used within functions declared with async
. It tells JavaScript to wait for the resolution of a Promise before moving on to the next line of code. This makes asynchronous code look and behave more like synchronous code, improving readability and maintainability.
Code
async function hero(){
async function delay(number) {
return new Promise((resolve) => {
setTimeout(() => {
console.log("Hero is back!");
resolve("Heroine, I am coming");
}, number * 1000);
});
}
async function hero() {
let answer = await delay(1);
console.log(answer);
}
hero();
}
Certainly! Let's break down the code in a simpler way:
delay
Function:The
delay
function takes a parameternumber
, which represents the number of seconds to wait.Inside the
delay
function, aPromise
is created. This promise will resolve after the specified delay usingsetTimeout
.The
setTimeout
function is used to wait for a certain amount of time (given bynumber * 1000
milliseconds).When the timeout is reached, it logs "Hero is back!" to the console and resolves the promise with the message "Heroine, I am coming."
hero
Function:Inside the
hero
function, it uses theawait
keyword to pause the execution and wait for thedelay
function to complete.Specifically, it awaits the result of calling
delay(1)
, meaning it waits for 1 second (as specified in the argument).Once the delay is over, it continues the execution, and the result of the
delay
function (in this case, "Heroine, I am coming") is stored in the variableanswer
.Finally, it logs the value of
answer
to the console.
Calling the
hero
Function:The
hero
function is called at the end of the code.When you run the script, it triggers the
hero
function, and you'll see the messages logged to the console after the specified delay.
In summary, this code simulates a situation where a hero is taking some time to come back, and the hero
function logs a message indicating that the hero is back after a delay of 1 second.
Understanding Web APIs:
Web APIs serve as intermediaries that enable the interaction between different software systems. They provide a set of rules and protocols for building and interacting with web services, allowing developers to access and manipulate data from remote servers. These APIs can be used for various purposes, such as retrieving data from a database, integrating with third-party services, or even creating your own services for others to consume.
HTTP Requests:
- Web APIs communicate using the HTTP protocol, primarily through two types of requests: GET and POST. GET requests retrieve data, while POST requests submit data to the server.
Fetch API:
- The Fetch API is a modern JavaScript interface for making network requests. It provides a cleaner and more powerful alternative to the older XMLHttpRequest.
fetch('https://api.example.com/data') .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Error:', error));
Asynchronous JavaScript (Async/Await):
- Asynchronous programming is crucial when working with Web APIs to prevent blocking the main thread. Async/await is a syntax for handling promises more comfortably.
async function fetchData() { try { const response = await fetch('https://api.example.com/data'); const data = await response.json(); console.log(data); } catch (error) { console.error('Error:', error); }} fetchData();
Handling API Responses:
Proper handling of API responses is essential. It involves checking for errors, parsing data, and updating the UI accordingly.
// Simulating a web API request function function fetchDataFromAPI() { const apiUrl = 'https://jsonplaceholder.typicode.com/todos/1'; return new Promise((resolve, reject) => { // Simulating an asynchronous operation, like fetching data from an API fetch(apiUrl) .then(response => { if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } return response.json(); }) .then(data => resolve(data)) .catch(error => reject(error)); }); } // Async function using async/await async function getData() { try { const result = await fetchDataFromAPI(); console.log(result); } catch (error) { console.error(error); } } // Using Promises directly fetchDataFromAPI() .then(result => console.log(result)) .catch(error => console.error(error)); // Calling the async function getData();
In this example, we are fetching data from the JSONPlaceholder API using the fetch
function. The fetchDataFromAPI
function returns a Promise that resolves with the fetched data or rejects with an error message. The getData
function demonstrates the use of async/await
, and the fetchDataFromAPI().then().catch()
structure shows the use of Promises directly.
Conclusion
Till now, we explored the foundational concept of Promises and their methods, providing a robust tool for managing asynchronous operations in JavaScript. Delving into the powerful combination of async/await
enhanced code readability and synchronous-like structure. We also harnessed the capabilities of Web APIs to interact with external resources seamlessly. This journey through Promises, async/await
, and Web APIs equips developers with the essential tools to write efficient and organized asynchronous JavaScript code.