Skip to content

Asynchronous Programming Review

A computer program is a set of instructions for manipulating information.

Up to now, the information displayed in our components has come from hard-coded data in our main.js. A far more realistic scenario is one where data come from some back-end storage such as a database. In this demo, we’ll examine fetching data for our components.

In this lesson, we introduce asynchronous JavaScript and the fetch API.

We will extend the reactive, component-based application built in previous lessons so that:

  • Data is loaded asynchronously from a backend API
  • The UI renders after data is fetched
  • Components react to data arriving over time

We are still not using a framework. The goal is to understand the mental model that frameworks later abstract.

At the end of this class, you should be able to…

  • Explain the JavaScript event loop and differentiate between synchronous and asynchronous operations.
  • Demonstrate how to use Promises and async/await to manage asynchronous tasks.
  • Apply error-handling strategies to ensure reliable execution of asynchronous code.

Reinforce the visual model of the event loop to support conceptual understanding.

Encourage students to experiment with debugging asynchronous code to reveal timing behaviour.


Grab the starter kit code for your Workbook by running the following in the VS Code terminal at the root of your workbook.

Terminal window
pnpm dlx tiged --disable-cache --force DG-InClass/SDEV-2150-A01-Sep-2026/sk/day-05/example/lesson-05-starter ./src/lesson-05

The first thing to note about this starter kit is that it’s comprised of two projects:

  • Directorybackend/ Data provided via a separate project
    • …
  • Directoryfrontend/ Web project consuming a backend API
    • …

The backend/ project is a simple server running on port 3000 that exposes the following endpoints:

# List all resources
GET /resources
# Get one resource by id
GET /resources/:id
# Create a resource
POST /resources
Content-Type: application/json
# Update a resource
PUT /resources/:id
Content-Type: application/json
# Delete a resource
DELETE /resources/:id

To understand the structure of the data being represented, examine the backend/resources.json and the backend/README.md.

Given that we are working with two projects, both need to be started in the terminal.

  1. Open two separate terminal windows in VS Code. Perform an install and run in both of them.

    ~/src/lesson-05/backend/
    pnpm install
    pnpm start
    ~/src/lesson-05/frontend/
    pnpm install
    pnpm dev
  2. Confirm that the backend is working by opening a browser to http://localhost:3000/resources. You should see data in JSON format.

  3. Confirm that the frontend is working by opening another browser tab to http://localhost:5173. You should see the website with the components

With our backend in place serving JSON data, it’s time to focus on editing our frontend code to make use of the API endpoint.

  1. Begin by removing the hard-coded data from main.js.

    ~/src/js/main.js
    const resultData = [
    {
    id: 'tutoring',
    title: 'Peer Tutoring Centre',
    category: 'Academic',
    summary: 'Drop-in tutoring and study support.',
    location: 'Building W, Room W101',
    hours: 'Mon-Thu 10:00-16:00',
    contact: 'tutoring@nait.ca',
    virtual: false,
    openNow: true,
    },
    {
    id: 'counselling',
    title: 'Counselling Services',
    category: 'Wellness',
    summary: 'Confidential mental health supports.',
    location: 'Virtual and in-person',
    hours: 'Mon-Fri 09:00-17:00',
    contact: 'wellness@nait.ca',
    virtual: true,
    openNow: true,
    },
    {
    id: 'bursaries',
    title: 'Student Awards and Bursaries',
    category: 'Financial',
    summary: 'Funding options and application help.',
    location: 'Student Services, Main Floor CAT',
    hours: 'Mon-Fri 10:00-15:00',
    contact: 'awards@nait.ca',
    virtual: true,
    openNow: false,
    },
    {
    id: 'it',
    title: 'IT Service Desk',
    category: 'Tech',
    summary: 'Account access, Wi-Fi, MFA resets.',
    location: 'Library',
    hours: 'Mon-Fri 08:30-16:30',
    contact: 'it@nait.ca',
    virtual: false,
    openNow: true,
    },
    ];

    Notice that no data appears in our page.

  2. Add temporary code to fetch data from the API endpoint and pass to the component.

    ~/src/js/main.js
    // TODO: Remove this "smoke-test" call later on
    const response = await fetch('http://localhost:3000/resources');
    const data = await response.json();
    resultData = [...data];
    // TODO: Stage 1: After fetching from the API, pass the fetched resources into <resource-results>
    const resultsComponent = document.querySelector('resource-results');
    resultsComponent.results = resultData;
  3. Your page should now be showing data fetched from the API endpoint. If you want to experiment with slower connections, explore the documentation for throttling in Chrome and Edge.

  4. Modify the resource-results.js to make it recognize a source attribute.

    ~/src/js/components/resource-results.js
    // TODO: Stage 2: Observe the `source` attribute
    static get observedAttributes() {
    return ['source'];
    }
  5. Add the attributeChanged() callback.

    ~/src/js/components/resource-results.js
    attributeChangedCallback(name, oldValue, newValue) {
    if (name === 'source' && oldValue !== newValue) {
    // Check if connected before fetching
    if (this.isConnected) {
    // Fetch new data from the source URL
    console.log(`Fetch from ${newValue}`);
    }
    }
    }
  6. Create a private function to do the “heavy lifting” of the fetch.

    ~/src/js/components/resource-results.js
    async #fetchData(source) {
    try {
    const response = await fetch(source);
    if (!response.ok) {
    throw new Error(`Network response was not ok: ${response.statusText}`);
    }
    const data = await response.json();
    this.results = data;
    } catch (error) {
    console.error('Failed to fetch data:', error);
    }
    this.render();
    }
  7. Return to the attributeChanged() callback and make use of that private function.

    ~/src/js/components/resource-results.js
    attributeChangedCallback(name, oldValue, newValue) {
    if (name === 'source' && oldValue !== newValue) {
    // Check if connected before fetching
    if (this.isConnected) {
    // Fetch new data from the source URL
    console.log(`Fetch from ${newValue}`);
    this.#fetchData(newValue);
    }
    }
    }
  8. Add the source attribute to your custom element’s markup.

    ~/src/index.html
    <resource-results class="col-12 col-lg-4"></resource-results>
    <resource-results class="col-12 col-lg-4" source="http://localhost:3000/resources"></resource-results>

In the starter kit, you will find a homework.md that corresponds to the content in this lesson.