CLOSE

Asynchronous JavaScript allows your code to initiate long-running operations—like network requests, file I/O, or timers—without blocking the main execution thread. Although JavaScript is single-threaded, its asynchronous model makes it feel concurrent. Here’s how it works:

The Event Loop

  • Single-threaded Nature: JavaScript runs on a single thread, meaning only one piece of code executes at a time.
  • Non-blocking I/O: The runtime uses an event loop to handle asynchronous operations. When an async task (e.g., a network request) is initiated, the task is offloaded (often to the browser or Node.js APIs). Once the task completes, a callback is queued.
  • Execution Queue: The event loop continuously checks the message queue and pushes queued callbacks into the call stack when the stack is clear.

This design lets JavaScript perform long-running operations without freezing the UI or delaying other tasks.

Asynchronous Patterns

Callbacks

Callbacks are the traditional way to handle asynchronous operations. They’re functions passed as arguments that execute once the asynchronous task completes.

  • Functions passed as arguments to be executed later once a task completes.
  • Example:

    setTimeout(() => {
      console.log('This runs after 2 seconds');
    }, 2000);
    
  • Drawback: Can lead to callback hell when callbacks are nested deeply.

Promises

Promises provide a cleaner way to manage asynchronous code by chaining operations and handling errors in a centralized manner.

  • Objects that represent the eventual completion (or failure) of an async operation.
  • Example:

    fetch('https://api.example.com/data')
      .then(response => response.json())
      .then(data => console.log(data))
      .catch(error => console.error(error));
    
  • Benefits: They provide a cleaner way to chain asynchornous operations and handle errors.

Async/Await

Async/await further simplifies working with promises by allowing you to write asynchronous code that reads like synchronous code.

  • Syntactic sugar built on top of Promises that makes asynchronous code look and behave more like synchronous code.
  • Example:

    async function fetchData() {
      try {
        const response = await fetch('https://api.example.com/data');
        const data = await response.json();
        console.log(data);
      } catch (error) {
        console.error(error);
      }
    }
    
    fetchData();
    
  • Benefits: Improves readability and error handling with try/catch blocks.