Asynchronous

JavaScript is often used for tasks that take time, like fetching data from a server or waiting for user actions. To keep your application responsive, JavaScript handles these tasks asynchronously. This means it doesn't wait for one task to finish before starting the next.

What is Asynchronous JavaScript?

In synchronous programming, tasks are executed one after the other. In asynchronous programming, tasks that take time run in the background, allowing other tasks to continue.

Example: Synchronous JavaScript

Javascript
Copy
console.log("Task 1");
console.log("Task 2");
console.log("Task 3");
// Outputs:
// Task 1
// Task 2
// Task 3

Example: Asynchronous JavaScript

Javascript
Copy
console.log("Task 1");

setTimeout(() => {
  console.log("Task 2");
}, 2000); // Waits 2 seconds

console.log("Task 3");
// Outputs:
// Task 1
// Task 3
// Task 2 (after 2 seconds)

Common Asynchronous Operations

  1. Fetching data from APIs
  2. Reading or writing files
  3. Timers (setTimeout and setInterval)
  4. User interactions like clicks or inputs

Callbacks

A callback is a function passed as an argument to another function. It's executed after the first function finishes its task.

Example: Using Callbacks

Javascript
Copy
function greetUser(name, callback) {
  console.log("Hello, " + name);
  callback();
}

function sayGoodbye() {
  console.log("Goodbye!");
}

greetUser("Alice", sayGoodbye);
// Outputs:
// Hello, Alice
// Goodbye!

Drawback of Callbacks: Callback Hell

When multiple callbacks are nested, the code can become hard to read and maintain.

Javascript
Copy
setTimeout(() => {
  console.log("Step 1");
  setTimeout(() => {
    console.log("Step 2");
    setTimeout(() => {
      console.log("Step 3");
    }, 1000);
  }, 1000);
}, 1000);

Promises

A Promise represents a task that will complete in the future. It can either:

  • Resolve (successful result)
  • Reject (error occurred)

Syntax of a Promise

Javascript
Copy
let promise = new Promise((resolve, reject) => {
  // Asynchronous task
  if (/* success */) {
    resolve("Task completed");
  } else {
    reject("Task failed");
  }
});

Using Promises

Javascript
Copy
let fetchData = new Promise((resolve, reject) => {
  let success = true; // Simulate success or failure
  if (success) {
    resolve("Data fetched successfully");
  } else {
    reject("Error fetching data");
  }
});

fetchData
  .then((message) => {
    console.log(message); // If resolved
  })
  .catch((error) => {
    console.log(error); // If rejected
  });

Chaining Promises

Javascript
Copy
fetchData
  .then((message) => {
    console.log(message);
    return "Next step";
  })
  .then((nextMessage) => {
    console.log(nextMessage);
  })
  .catch((error) => {
    console.log(error);
  });

Async and Await

The async and await keywords make working with asynchronous code easier and more readable. They allow you to write asynchronous code that looks like it's synchronous.

Syntax

  • Use async to declare a function that works with await.
  • Use await to wait for a promise to resolve before moving to the next line.

Example:

Javascript
Copy
async function fetchData() {
  try {
    let data = await new Promise((resolve, reject) => {
      setTimeout(() => resolve("Data fetched!"), 2000);
    });
    console.log(data);
  } catch (error) {
    console.log("Error:", error);
  }
}

fetchData();
// Outputs (after 2 seconds): Data fetched!

Combining Async/Await and Promises

You can use async/await for cleaner code, especially when working with multiple asynchronous tasks.

Example: Fetching Data

Javascript
Copy
function getData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve("Data fetched"), 2000);
  });
}

async function processData() {
  try {
    let result = await getData();
    console.log(result);
    console.log("Processing complete");
  } catch (error) {
    console.log("Error:", error);
  }
}

processData();
// Outputs:
// (After 2 seconds) Data fetched
// Processing complete

Real-World Example: Fetching an API

Using fetch and Promises

Javascript
Copy
fetch("https://jsonplaceholder.typicode.com/posts/1")
  .then((response) => response.json())
  .then((data) => {
    console.log("Post:", data);
  })
  .catch((error) => {
    console.log("Error:", error);
  });

Using Async/Await

Javascript
Copy
async function getPost() {
  try {
    let response = await fetch("https://jsonplaceholder.typicode.com/posts/1");
    let data = await response.json();
    console.log("Post:", data);
  } catch (error) {
    console.log("Error:", error);
  }
}

getPost();

Error Handling in Asynchronous Code

1. Using .catch() for Promises

Javascript
Copy
fetch("invalid-url")
  .then((response) => response.json())
  .catch((error) => console.log("Fetch Error:", error));

2. Using try...catch with Async/Await

Javascript
Copy
async function fetchData() {
  try {
    let response = await fetch("invalid-url");
    let data = await response.json();
  } catch (error) {
    console.log("Error:", error);
  }
}

fetchData();