Callbacks, Promise & Async/await | Javascript Hindi Course For Beginners ( 2023 ) #11

What is Async Programming ?

Async programming in JavaScript is a programming paradigm that allows you to write non-blocking code that doesn't block the main thread of execution. It enables JavaScript code to handle time-consuming operations such as fetching data from a remote server or reading data from a file without blocking the execution of other code.
Traditionally, JavaScript is a single-threaded language, which means that it can only execute one task at a time. This can cause problems when trying to perform tasks that are time-consuming, such as making an HTTP request, where the code has to wait for a response from the server before it can continue executing. This can result in the code appearing to hang or freeze.
To solve this problem, JavaScript introduced the concept of asynchronous programming, which allows you to write non-blocking code that can execute other tasks while it waits for a time-consuming task to complete. This is achieved using callback functions, promises, and async/await keywords.
 
  1. Callback functions are functions that are passed as arguments to other functions and are called when that function has completed its task. Callbacks are useful for handling asynchronous operations such as making an HTTP request.
  1. Promises are objects that represent the eventual completion or failure of an asynchronous operation and can be used to chain multiple asynchronous operations together.
  1. Async/await is a newer and more convenient way to handle asynchronous operations in JavaScript. It allows you to write asynchronous code that looks synchronous and is easier to read and maintain. The "async" keyword is used to indicate that a function is asynchronous, and the "await" keyword is used to wait for the completion of an asynchronous operation.
 

Callbacks

a callback function is a function that is passed as an argument to another function and is called when the other function has completed its task. The function that receives the callback is responsible for executing it at the appropriate time.
Callbacks are used extensively in asynchronous programming in JavaScript to handle events and to perform non-blocking operations.
function fetchData(callback) { setTimeout(() => { const data = [1, 2, 3, 4, 5]; callback(data); }, 2000); } function processData(data) { console.log(data.map(item => item * 2)); } fetchData(processData); // Pass processData function as a callback
 

Callback hell

Callback hell, also known as "pyramid of doom," is a term used to describe a situation in asynchronous programming where multiple levels of nested callbacks are used, making the code difficult to read, maintain, and debug. This occurs when multiple asynchronous functions need to be executed sequentially or when one function depends on the result of another function.
getData((error, data) => { if (error) { console.error(error); } else { processData(data, (error, processedData) => { if (error) { console.error(error); } else { saveData(processedData, (error) => { if (error) { console.error(error); } else { console.log('Data saved successfully!'); } }); } }); } });
 

Promise

A promise in JavaScript is an object representing the eventual completion or failure of an asynchronous operation and its resulting value. It's a way of handling asynchronous code in a more readable and predictable way.
A promise has three states:
  1. Pending: The initial state when the promise is created.
  1. Fulfilled: The state when the promise is resolved successfully with a value.
  1. Rejected: The state when the promise is rejected with an error.
const fetchData = () => { return new Promise((resolve, reject) => { setTimeout(() => { const data = { name: 'John', age: 30 }; resolve(data); }, 2000); }); }; fetchData() .then(data => { console.log(data); }) .catch(error => { console.error(error); });
 
Promises can also be chained together to handle multiple asynchronous operations in sequence, or to handle errors in a more readable way
fetchData() .then(data => { return processData(data); }) .then(processedData => { return saveData(processedData); }) .then(() => { console.log('Data saved successfully!'); }) .catch(error => { console.error(error); }).finally(() => { console.log('Promise finished executing!'); });
 

Static methods of the Promise class

  1. Promise.all(iterable): This method returns a new Promise object that is fulfilled when all of the promises in the iterable argument have been fulfilled. If any of the promises are rejected, the entire Promise.all call is rejected. The result is an array of the fulfilled values in the order they were passed.
  1. Promise.allSettled()method returns a promise that resolves with an array of objects representing the status of each promise in the input iterable when all of the promises have settled. The objects returned by Promise.allSettled() have two properties: status and valueor reason, depending on whether the promise fulfilled or rejected.
  1. Promise.race(iterable): This method returns a new Promise object that is fulfilled or rejected as soon as one of the promises in the iterable argument is fulfilled or rejected. The result is the value or reason of the first promise to settle.
  1. Promise.any()method returns a promise that fulfills with the value of the first input promise that fulfills. If all input promises are rejected, the returned promise is rejected with an AggregateErrorcontaining all of the rejection reasons.
  1. Promise.reject(reason): This method returns a new Promise object that is rejected with the given reason.
    1. Promise.resolve(value): This method returns a new Promise object that is resolved with the given value. If the value is already a Promise, it is returned as-is.
    2.  

Async & Await

async/await is a syntax feature in modern versions of JavaScript (ES2017 or later) that allows developers to write asynchronous code in a more readable and concise way.is a syntax feature in modern versions of JavaScript (ES2017 or later) that allows developers to write asynchronous code in a more readable and concise way.
 

Async

async is a keyword that is used to define a function as asynchronous. An asynchronous function is one that can perform long-running tasks without blocking the execution of other code in the same thread.
When a function is marked as async, it returns a Promise that resolves to the return value of the function or to an error if one occurs. The Promise allows you to chain asynchronous operations together and handle the results using then() and catch() methods.
 
// Async Example // Using Promise const channelName = new Promise((resolve, reject) => { return resolve("Do Some Coding"); }); channelName.then((channel) => { console.log(channel); }); // Using Async async function channelName(){ return "Do Some Coding"; } channelName.then((channel) => { console.log(channel); }); // Async Function always returns a promise. // all values and erros are wrapped inside a promise.

Await

await is a keyword that is used within an async function to pause the execution of the function until a Promise is resolved. When used with a Promise, the awaitkeyword waits for the Promise to resolve and then returns the resolved value.
// Using promise const fetchData = new Promise((resolve, reject) => { const error = false; if (error) { reject("Some Error"); } setTimeout(() => { const data = [1, 2, 3, 4, 5]; resolve(data); }, 2000); }); fetchData .then((data) => { console.log(data); }) .catch((error) => { console.log(error); }); // using async await async function fetchData() { const error = true; if (error) { throw new Error("Some Error"); } else { const data = [1, 2, 3, 4, 5]; return data; } } async function processData() { try { const data = await fetchData(); console.log(data); } catch (error) { console.log(error); } } processData();
 

Try Catch

try...catch is a construct used for error handling. It allows you to catch and handle errors that may occur during the execution of a code block.
The try block is used to enclose the code that might throw an error. If an error occurs within the try block, the execution of the block is stopped, and the control is passed to the catch block. The catch block is used to handle the error and provide an appropriate response.
 
try { // code that might throw an error const result = doSomething(); console.log(result); } catch (error) { // handle the error console.error(error); }
 

Error Object

An error object is a special type of object that contains information about an error that has occurred during the execution of a program. When an error occurs, an error object is usually created and thrown, and the program execution is stopped or diverted to an error handling code block.
function divide(a, b) { if (b === 0) { throw new Error("Cannot divide by zero"); } return a / b; } try { const result = divide(10, 0); console.log(result); } catch (error) { console.error(error.name); // "Error" console.error(error.message); // "Cannot divide by zero" console.error(error.stack); // stack trace of the error }
 
some common built-in error classes in JavaScript:
  • Error: the base error class that all other error classes inherit from. This class is used to create custom error classes and is usually not used directly.
  • SyntaxError: an error that occurs when there is a syntax error in the program code, such as a missing semicolon or an extra bracket.
  • TypeError: an error that occurs when a value is of the wrong type, such as trying to call a function on a null or undefined value.
  • ReferenceError: an error that occurs when a reference to a variable or function that does not exist is made.
  • RangeError: an error that occurs when a value is out of the range of acceptable values, such as trying to create an array with a negative length.
 

Finally Block

try { // Block of code to be attempted } catch (error) { // Block of code to handle the error } finally { // Block of code to be executed regardless of whether an error occurred or not }
 

Questions

// 1 Perform Network Request fetch('https://jsonplaceholder.typicode.com/posts') .then(response => response.json()) .then(json => console.log(json)) // Using Async And Await Syntax