JavaScript provides several mechanisms for handling asynchronous operations, with async and await being the most modern and widely used. Let's break them down along with other asynchronous keywords.

1. Async & Await

These keywords allow you to write asynchronous code that looks synchronous, making it easier to read and manage.

Async Function

  • Declaring a function as async means it always returns a Promise.
  • Inside an async function, you can use the await keyword to pause execution until a Promise resolves.

Example:

async function fetchData() {
  return "Hello, Async!";
}

fetchData().then(console.log); // Output: "Hello, Async!"

Await Keyword

  • The await keyword pauses the execution inside an async function until the Promise resolves, avoiding the need for .then().
  • Helps keep the code more readable compared to chaining .then() callbacks.

Example:

async function fetchData() {
  const data = await fetch("https://jsonplaceholder.typicode.com/todos/1");
  const json = await data.json();
  console.log(json);
}

fetchData();

2. Promises

Before async/await, JavaScript used Promises for handling asynchronous operations. A Promise represents a value that may be available now, or later, or never.

Example:

const myPromise = new Promise((resolve, reject) => {
  setTimeout(() => resolve("Promise Resolved!"), 2000);
});

myPromise.then(console.log); // Output after 2 seconds: "Promise Resolved!"

3. Callback Functions

Older JavaScript code often relied on callbacks, but they led to "callback hell" when too many nested functions were used.

Example:

function fetchData(callback) {
  setTimeout(() => {
    callback("Data received!");
  }, 2000);
}

fetchData(console.log); // Output after 2 seconds: "Data received!"

This approach became harder to maintain, leading to the rise of Promises and async/await.

4. Other Asynchronous Keywords

Promise.all()

Runs multiple Promises in parallel and waits for all of them to resolve.

const p1 = Promise.resolve("First");
const p2 = new Promise(resolve => setTimeout(() => resolve("Second"), 1000));

Promise.all([p1, p2]).then(console.log); // ["First", "Second"] after 1 sec

Promise.race()

Resolves as soon as one Promise resolves.

const p1 = new Promise(resolve => setTimeout(() => resolve("First"), 3000));
const p2 = new Promise(resolve => setTimeout(() => resolve("Second"), 1000));

Promise.race([p1, p2]).then(console.log); // Output: "Second" (fastest one wins)

When to Use Each Method?

  • Use async/await for cleaner and more readable asynchronous code.
  • Use Promises when working with APIs and chaining multiple async operations.
  • Use Promise.all() for running async tasks in parallel.
  • Use Promise.race() when only the first resolved result matters.