JavaScript Asynchronous Programming

1. What is Asynchronous JavaScript?

JavaScript is single-threaded, meaning it can only do one thing at a time. Asynchronous programming allows long-running tasks (like API calls or timers) to run in the background without blocking the main thread, ensuring the user interface remains responsive.

2. Callbacks

A callback is a function passed as an argument to another function, which is then executed after the outer function has completed. This was the traditional way to handle async operations.

function greet(name, callback) {
    document.write("Hello, " + name);
    // Simulate a delay
    setTimeout(callback, 1000);
}

greet("Ragini", function() {
    document.write("The callback has been executed!");
});
        
Output will appear here...

Callback Hell

When multiple nested callbacks are used, it can lead to "Callback Hell" or the "Pyramid of Doom," making code hard to read and maintain.

3. Promises

A Promise is an object representing the eventual completion (or failure) of an asynchronous operation. It has three states: pending, fulfilled, or rejected.

let promise = new Promise((resolve, reject) => {
    let success = true;
    setTimeout(() => {
        if (success) {
            resolve("Promise resolved successfully!");
        } else {
            reject("Promise failed!");
        }
    }, 1500);
});

promise
    .then(result => document.write(result)) // Handles success
    .catch(error => document.write(error)); // Handles failure
        
Output will appear here...

4. async / await

async/await is modern "syntactic sugar" built on top of Promises. It makes asynchronous code look and behave more like synchronous code, making it much easier to read and write.

// A function that returns a promise
function wait(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

// An async function
async function run() {
    try {
        document.write("Start");
        await wait(2000); // Pauses execution for 2 seconds
        document.write("Finished after 2 seconds");
    } catch (error) {
        console.error("Something went wrong:", error);
    }
}

run();
        
Output will appear here...

5. Fetch API: A Real-World Example

async/await is perfect for fetching data from an API.

async function fetchUserData() {
    try {
        const response = await fetch('https://jsonplaceholder.typicode.com/users/1');
        const user = await response.json();
        document.write("User:", user.name);
    } catch (error) {
        console.error("Could not fetch user:", error);
    }
}

fetchUserData();
        
Output will appear here...

6. Comparison: Async Techniques

Feature Callback Promise Async/Await
Syntax Nested and complex Chained with .then() Clean and synchronous-like
Error Handling Manual (error-first) .catch() try...catch
Readability Low (Callback Hell) Good Excellent
Best Practice: Prefer async/await for modern asynchronous code as it offers the best readability and error handling. Understand Promises, as they are the foundation on which async/await is built.

Practice Questions

Test your understanding of Asynchronous JavaScript.

Easy

Q1: Explain and demonstrate a callback function.

  • Explain what a callback function is.
  • Write a function `fetchData` that accepts a `callback`.
  • Inside `fetchData`, use `setTimeout` to simulate a delay before executing the callback.
Easy

Q2: Handle errors in a Promise.

  • How do you handle a rejected Promise?
  • Write a code snippet showing a .then() for success and a .catch() for failure.
Medium

Q3: Create a basic Promise.

  • Create a new Promise that resolves after 2 seconds.
  • The resolved value should be the string "Success!".
  • Use .then() to log the result to the console.
Medium

Q4: Convert a Promise chain to async/await.

  • Create a helper function that returns a Promise which resolves after 2 seconds.
  • Write an async function.
  • Inside the async function, use await to pause execution until the Promise resolves.
  • Log the result.
Hard

Q5: Fetch API data using async/await.

  • Write an async function named fetchTodo.
  • Use fetch to get data from https://jsonplaceholder.typicode.com/todos/1.
  • Use a try...catch block to handle potential errors.
  • Parse the JSON response and log the data.

Answer

Code: