05 Asynchronous JavaScript
Syllabus:
1. Introduction to asynchronous programming
2.Callbacks
3.Promises
Creating and consuming promises
Chaining promises
Error handling with promises
4.Async/Await
1. Introduction to asynchronous programming
Asynchronous programming in JavaScript allows tasks to be executed independently of the main program flow.
Aspect | Description |
Non-Blocking | Asynchronous operations do not block the execution of the main program flow, allowing other code to run concurrently. |
Callbacks | Functions passed as arguments to handle asynchronous tasks once they are completed. |
Promises | Introduced in ES6, promises represent the eventual completion or failure of an asynchronous operation. |
Async/Await | A syntax introduced later in JavaScript to write asynchronous code that looks synchronous, improving readability. |
Event Loop | JavaScript's concurrency model that manages the execution of asynchronous tasks via the call stack and task queue. |
Common Use Cases | Handling tasks like fetching data from servers, interacting with databases, reading files, and non-blocking UI updates. |
2.Callbacks
Definition: A callback is a function passed as an argument to another function, which is then invoked or executed inside the outer function to complete some kind of action.
Usage in Asynchronous Operations: In asynchronous operations, callbacks are often used to handle the result of an asynchronous task, such as data retrieval. Once the asynchronous task completes, the callback function is called with the result.
3.Promises
Definition: A promise represents the eventual completion or failure of an asynchronous operation and its resulting value.
States:
Pending: Initial state, neither fulfilled nor rejected.
Fulfilled (Resolved): The operation completed successfully.
Rejected: The operation failed with an error.
Creation: Promises are created using the
Promise
constructor, which takes a function as an argument, commonly referred to as the executor function. This function receives two parameters:resolve
andreject
, which are functions used to settle the promise.
const myPromise = new Promise((resolve, reject) => {
// Asynchronous operation
if (/* operation successful */) {
resolve("Operation completed successfully");
} else {
reject("Operation failed");
}
});
Consuming Promises:
then()
: Used to handle the fulfillment of the promise. It takes two optional callbacks: one for the success case and one for the failure case.catch()
: Used to handle promise rejection, similar to the second argument ofthen()
.finally()
: Executes regardless of the promise state, useful for cleanup tasks.
myPromise
.then((result) => {
console.log("Success:", result);
})
.catch((error) => {
console.error("Error:", error);
})
.finally(() => {
console.log("Promise settled");
});
4.Async/Await
Async Functions:
The async
keyword is used to define an async function, which automatically returns a promise. Inside an async function, you can use the await
keyword to pause execution until a promise is settled (either resolved or rejected).
async function myAsyncFunction() {
const result = await someAsyncOperation();
return result;
}
Await Keyword:
The await
keyword can only be used inside async functions. It pauses the execution of the async function until the promise is settled. If the promise is resolved, await
returns the resolved value; if the promise is rejected, it throws an error that can be caught using a try...catch
block.
async function myAsyncFunction() {
try {
const result = await someAsyncOperation();
console.log(result);
} catch (error) {
console.error(error);
}
}
Sequential Execution:
Async/await allows you to write asynchronous code in a more synchronous-looking style, making it easier to understand and maintain. Code written using async/await tends to be more readable than equivalent code written using promises or callbacks.
async function fetchData() {
const firstData = await fetchFirstData();
const secondData = await fetchSecondData();
return [firstData, secondData];
}
Error Handling in async/await:
Error handling in async/await functions can be done using try...catch
blocks, which provide a more natural way to handle errors compared to promises.
async function myAsyncFunction() {
try {
const result = await someAsyncOperation();
console.log(result);
} catch (error) {
console.error("An error occurred:", error);
}
}
Parallel Execution:
You can use Promise.all()
with async/await to execute multiple asynchronous operations concurrently and await their completion.
async function fetchData() {
const [firstData, secondData] = await Promise.all([
fetchFirstData(),
fetchSecondData(),
]);
return [firstData, secondData];
}
4.Async/Await - ๐ yahoo baba
Synchronous vs Asynchronous Function Declaration and Invocations
// Synchronous function declaration
function test() {
return 'Hello';
}
// Synchronous function call
console.log(test());
Async Function Declaration and Invocation Comparison
// Asynchronous function declaration using async keyword
async function test() {
return 'Hello';
}
// Synchronous function call
console.log(test()); // Logs: Promise {<pending>}
// Asynchronous function call using Promise chaining
test().then((result) => {
console.log(result); // Logs: Hello
})
Various Ways to Define an Async Function
// Async function declaration
async function test() {
return 'Hello';
}
// Async function expression using function keyword
let test = async function () {
return 'Hello';
}
// Async arrow function expression with block body
let test = async () => {
return 'Hello';
}
// Async arrow function expression with implicit return
let test = async () => 'Hello';
Understanding Async Function Execution with Await
let fun = async () => {
console.log(2);
// console.log(3);
await console.log(3);
console.log(5);
}
console.log(1); // Logs: 1
fun(); // Invokes the async function
console.log(4); // Logs: 4
/* Expected Output:
1
2
3
4
5
*/
Asynchronous Data Fetching with Async/Await
let run = async () => {
// Fetch JSON data from a URL asynchronously
let res = await fetch('/05-Asynchronous_JS/data/student.json');
// Parse JSON response
let data = await res.json();
// Log entire data
console.log(data);
// Log the first element of data
console.log(data[0]);
// Log the age of the first element
console.log(data[0].age);
// Return the fetched data
// return data;
// SINGLE LINE CODE: Fetch JSON data and directly return it
return (await fetch('/05-Asynchronous_JS/data/student.json')).json();
}
// FileStudent data.json
[
{
"name": "Ayush Kumar",
"age": 19,
"city": "BH"
},
{
"name": "Rahul",
"age": 15,
"city": "BPL"
},
{
"name": "Ajay",
"age": 21,
"city": "Motihari"
}
]
// Invoke the asynchronous function
let r = run();
// Log the promise returned by the async function
console.log(r);
/* Expected Output:
Promise {<pending>}
[ { name: 'John', age: 25 }, { name: 'Alice', age: 30 }, { name: 'Bob', age: 28 } ]
{ name: 'John', age: 25 }
25
*/
// Execute the asynchronous function and handle its returned promise
run()
.then((res) => {
// Log the resolved data
console.log(res);
// Log the third element of the resolved data
console.log(res[2]);
})
// Handle errors if any
.catch((err) => console.log(err));
Handling Errors with Async/Await and Promise Chaining
let sun = async () => {
try {
// Fetch JSON data from a URL asynchronously
let res = await fetch('/05-Asynchronous_JS/data/student.json');
// Parse JSON response
let data = await res.json();
// Log entire data
console.log(data);
// Log the first element of data
console.log(data[0]);
// Log the age of the first element
console.log(data[0].age);
// Return the fetched data
return data;
} catch (error) {
// Handle errors
console.log('Error!', error);
}
}
// Execute the asynchronous function and handle its returned promise
sun()
.then((res) => {
// Log the resolved data
console.log("Using .then method : ", res);
// Log the third element of the resolved data
console.log(res[2]);
});