Skip to main content

Asynchronous JavaScript and DOM Updates

In modern web applications, many tasks like fetching data from APIs, loading images, and processing large files are handled asynchronously to avoid blocking the user interface. In this section, you’ll learn how to work with asynchronous functions and how to update the DOM based on asynchronous operations.

Understanding Asynchronous JavaScript with Promises and async/await

Asynchronous code lets JavaScript run tasks in the background without blocking the main thread. Promise objects represent eventual completion (or failure) of an async operation, while async/await syntax simplifies writing asynchronous code.

  1. Basic Promise Example

    const fetchData = new Promise((resolve, reject) => {
    setTimeout(() => {
    const data = { user: "John", age: 25 };
    resolve(data); // Simulates fetching data
    }, 2000); // 2-second delay
    });

    fetchData.then((data) => {
    console.log("Data fetched:", data);
    }).catch((error) => {
    console.error("Error fetching data:", error);
    });

    Explanation: This Promise simulates a data-fetching delay of 2 seconds. If successful, the data is logged to the console; if an error occurs, it’s caught and logged.

  2. Async/Await Syntax

    async function getData() {
    try {
    const data = await fetchData; // Wait for the Promise to resolve
    console.log("Data fetched:", data);
    } catch (error) {
    console.error("Error fetching data:", error);
    }
    }

    getData();

    Explanation: getData is an asynchronous function that waits for fetchData to complete. The await keyword pauses the function until the Promise resolves.

Fetching Data from an API and Updating the DOM

With asynchronous functions, you can fetch live data from an API and update the DOM based on the retrieved information.

  1. Example: Fetching Data from a JSON Placeholder API

    <button id="load-user">Load User</button>
    <div id="user-info"></div>
    const loadUserButton = document.getElementById("load-user");
    const userInfo = document.getElementById("user-info");

    loadUserButton.addEventListener("click", async () => {
    try {
    const response = await fetch("https://jsonplaceholder.typicode.com/users/1");
    const user = await response.json(); // Parse JSON data

    userInfo.innerHTML = `
    <p><strong>Name:</strong> ${user.name}</p>
    <p><strong>Email:</strong> ${user.email}</p>
    <p><strong>City:</strong> ${user.address.city}</p>
    `;
    } catch (error) {
    userInfo.textContent = "Error loading user data.";
    console.error("Error:", error);
    }
    });

    Explanation: When "Load User" is clicked, the function fetches user data from the JSONPlaceholder API and updates the user-info div with the user’s name, email, and city.

Updating the DOM in Response to Async Actions

Async actions often require UI changes, such as showing loading indicators or displaying error messages.

  1. Example: Displaying a Loading Indicator

    <button id="load-posts">Load Posts</button>
    <div id="posts"></div>
    const loadPostsButton = document.getElementById("load-posts");
    const postsDiv = document.getElementById("posts");

    loadPostsButton.addEventListener("click", async () => {
    postsDiv.textContent = "Loading posts...";

    try {
    const response = await fetch("https://jsonplaceholder.typicode.com/posts?_limit=3");
    const posts = await response.json();

    postsDiv.innerHTML = posts.map(post => `
    <div>
    <h3>${post.title}</h3>
    <p>${post.body}</p>
    </div>
    `).join(""); // Render all posts at once
    } catch (error) {
    postsDiv.textContent = "Error loading posts.";
    console.error("Error:", error);
    }
    });

    Explanation: When "Load Posts" is clicked, "Loading posts..." appears while the data is being fetched. After fetching, the posts are displayed in the postsDiv container. If an error occurs, a message is shown instead.

Handling Multiple Asynchronous Operations with Promise.all

If you need to fetch multiple resources simultaneously, Promise.all can be helpful.

  1. Fetching Multiple Resources with Promise.all

    async function fetchMultiple() {
    try {
    const [userResponse, postsResponse] = await Promise.all([
    fetch("https://jsonplaceholder.typicode.com/users/1"),
    fetch("https://jsonplaceholder.typicode.com/posts?_limit=2")
    ]);

    const user = await userResponse.json();
    const posts = await postsResponse.json();

    console.log("User:", user);
    console.log("Posts:", posts);
    } catch (error) {
    console.error("Error fetching data:", error);
    }
    }

    fetchMultiple();

    Explanation: This code fetches user and post data concurrently. Both requests are awaited simultaneously, and if either fails, it’s caught in the catch block.