Lecture Notes Of Day 15: Asynchronous JavaScript

Rashmi Mishra
0

 Lecture Notes Of Day 15

Asynchronous JavaScript

Objective:

The objective of this class is to help students understand how JavaScript handles asynchronous operations, allowing for non-blocking execution of tasks. This will include learning about callbacks, promises, and the more modern async/await syntax for managing asynchronous code.


What is Asynchronous JavaScript?

In JavaScript, asynchronous programming is a method of handling tasks that take time (like data fetching, file reading, or network requests) without blocking the rest of the code from executing. Asynchronous operations allow JavaScript to execute other code while waiting for a task to complete.

Synchronous code, on the other hand, executes line by line. This can be inefficient, especially if there are tasks that take a long time to complete.

Asynchronous operations are commonly used in situations like:

  • Making network requests (e.g., loading data from an API)
  • Reading from or writing to a file
  • Handling user input events

1. Callbacks:

A callback is a function that is passed as an argument to another function, and it is executed once the asynchronous operation is complete. Callbacks allow us to handle the result of an asynchronous operation.

Example of a Callback:

function fetchData(callback) {

  setTimeout(() => {

    console.log("Data fetched successfully.");

    callback("Data is here!");

  }, 2000);

}

 

function handleData(data) {

  console.log(data);

}

 

fetchData(handleData);

Explanation:

  • fetchData simulates an asynchronous operation (e.g., fetching data from a server).
  • The setTimeout function delays the execution of the code for 2 seconds to simulate an async task.
  • Once the data is fetched, the handleData function is called via the callback to process the result.

Callback Problem (Callback Hell): 

One of the main issues with callbacks is that they can lead to deeply nested functions, which can make the code difficult to read and maintain. This is often referred to as "callback hell."

Example of Callback Hell:

fetchData(function(data) {

  processData(data, function(result) {

    saveData(result, function(response) {

      console.log('Data saved: ', response);

    });

  });

});

As you can see, callbacks can become hard to manage when they are nested. This is where promises and async/await come in handy.


2. Promises:

A promise is a modern alternative to callbacks. A promise represents a value that may not be available yet but will be resolved in the future. Promises can be in one of three states:

1.Pending: The initial state; the promise is still being processed.

2.Resolved (Fulfilled): The asynchronous operation has completed successfully.

3.  Rejected: The asynchronous operation has failed.

Promise Syntax:

let promise = new Promise(function(resolve, reject) {

  // Simulating a task with setTimeout

  setTimeout(() => {

    let success = true; // You can change this to false to simulate an error

    if (success) {

      resolve("Data fetched successfully!");

    } else {

      reject("Error fetching data.");

    }

  }, 2000);

});

 

promise

  .then(result => {

    console.log(result); // Success: 'Data fetched successfully!'

  })

  .catch(error => {

    console.log(error); // Failure: 'Error fetching data.'

  });

Explanation:

  • A Promise is created, and inside its executor function, an asynchronous operation (simulated by setTimeout) is performed.
  • If the operation is successful, resolve() is called, passing the result.
  • If an error occurs, reject() is called with the error message.
  • The then() method is used to handle the resolved value, and catch() is used to handle any errors.

Promise Chaining: Promises allow you to chain multiple .then() calls for handling sequential asynchronous operations.

fetchData()

  .then(response => {

    console.log(response);

    return processData(response);

  })

  .then(result => {

    console.log(result);

    return saveData(result);

  })

  .then(finalResponse => {

    console.log(finalResponse);

  })

  .catch(error => {

    console.log("Error:", error);

  });

Chaining .then() calls makes the code cleaner and more readable compared to nested callbacks.


3. Async/Await:

async and await are keywords introduced in ES8 (ECMAScript 2017) that simplify working with promises. async is used to declare a function that will return a promise, and await is used to pause the execution of the code until the promise is resolved.

Async Function:

An async function automatically returns a promise and allows you to use await within it.


async function fetchData() {

  let data = await fetch('https://jsonplaceholder.typicode.com/posts');

  let json = await data.json();

  return json;

}

 

fetchData().then(data => console.log(data));

Explanation:

  • fetchData is an async function that fetches data from an API.
  • Inside the function, we use await to wait for the promise returned by fetch to resolve.
  • The result is then processed using await for parsing the JSON data.

Error Handling with Async/Await:

Handling errors in async/await is easy using try...catch blocks:

async function fetchData() {

  try {

    let response = await fetch('https://jsonplaceholder.typicode.com/posts');

    if (!response.ok) {

      throw new Error('Network response was not ok');

    }

    let data = await response.json();

    console.log(data);

  } catch (error) {

    console.error('There was a problem with the fetch operation:', error);

  }

}

Explanation:

  • If an error occurs (e.g., network issue or invalid response), it will be caught in the catch block and logged.

Async/Await vs Promises:

  • async/await provides a more synchronous way of handling asynchronous code, making it easier to read and write.
  • Promises, while powerful, often require chaining .then() and .catch(), which can become cumbersome in complex scenarios.

Key Points to Remember:

  • Callbacks are functions passed to other functions and executed later, but they can result in complex nested structures (callback hell).
  • Promises represent the eventual completion (or failure) of an asynchronous operation and provide a cleaner syntax using .then() and .catch() for handling success and failure.
  • Async/Await simplifies promises, allowing asynchronous code to be written in a more readable, synchronous-like manner.

Practice Exercise:

Task 1: Write a function fetchDataFromAPI() that simulates fetching data from an API. It should return a promise that resolves with a message after 2 seconds. Use async/await to call this function and log the result.

Task 2: Using promises, write a program that performs the following tasks sequentially:

1.  Fetch data from one API (simulate this using setTimeout).

2.  Process the data (simulate this by adding some text to the fetched data).

3.  Log the final result.


By the end of this session, students should have a solid understanding of how asynchronous JavaScript works and be comfortable using callbacks, promises, and async/await to handle asynchronous operations in their code.
Tags

Post a Comment

0Comments

Post a Comment (0)