# Async and Await

JavaScript has async and await too, working just like C#'s. An async function can await a promise, such as fetch's, and read like ordinary code, with try and catch for errors. Use it to load data into the page and send a form to an API.

Journeyman · JavaScript · REST API · Updated November 3, 2026

## After this lesson you can

- Write an async function that awaits fetch and response.json, with try and catch for errors
- Load data from an API into the page, and send a form's data to it, without reloading the page

## Key takeaways

- An `async` function can `await` a promise, such as `fetch`'s, and always returns a promise, as a C# one returns a `Task`.
- With `await`, an ordinary `try` and `catch` handles both a thrown error and a `fetch` that gets no answer.
- Call `event.preventDefault()` in a form's `submit` handler, then send its data with `fetch`, so the page never reloads.
- Put text from a user or an API into the page with `textContent`, not `innerHTML`, so it can't run as code.

Chains of `then` work, but they get hard to read as the steps pile up. JavaScript has the answer you already know from C#: **`async`** and **`await`**.

## The same request, awaited

```javascript
async function showCategory(id) {
    const response = await fetch(`/api/categories/${id}`);
    const category = await response.json();
    console.log(`${category.categoryName}: ${category.description}`);
}

showCategory(8);
```

```text
Seafood: Seaweed and fish
```

It works exactly like C#:

- **`async`** before `function` allows `await` inside it. An async function always returns a promise, as a C# one returns a `Task`.
- **`await`** waits for a promise and gives its result: `await fetch(...)` gives the response, `await response.json()` gives the object.
- While it waits, the browser is free to do other things, such as respond to clicks, so the page never freezes.

Arrow functions can be async too: `const showCategory = async id => { ... };`.

## try and catch

With `await`, errors are caught with an ordinary **`try`** and **`catch`**, instead of `.catch(...)`:

```javascript
async function loadCategory(id) {
    try {
        const response = await fetch(`/api/categories/${id}`);
        if (!response.ok) {
            throw new Error(`The API answered ${response.status}`);
        }
        const category = await response.json();
        console.log(category.categoryName);
    } catch (error) {
        console.log(`Couldn't load category ${id}: ${error.message}`);
    }
}

await loadCategory(7);
await loadCategory(300);
```

```text
Produce
Couldn't load category 300: The API answered 404
```

The `catch` runs both for the `throw` (the API answered, but not with success) and for a failed `fetch` (no answer at all), just as with `.catch`.

## A page that uses the API

Here's a whole page for the `wwwroot` folder: it lists the categories, and has a form to add one. First `wwwroot/index.html`:

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Categories</title>
</head>
<body>
    <h1>Categories</h1>
    <ul id="categories"></ul>
    <p id="message"></p>

    <form id="add-category">
        <input id="name" placeholder="Category name" required>
        <button type="submit">Add</button>
    </form>

    <script src="app.js"></script>
</body>
</html>
```

Then `wwwroot/app.js`:

```javascript
const list = document.getElementById('categories');
const message = document.getElementById('message');
const form = document.getElementById('add-category');
const nameInput = document.getElementById('name');

async function loadCategories() {
    try {
        const response = await fetch('/api/categories');
        if (!response.ok) {
            throw new Error(`The API answered ${response.status}`);
        }
        const categories = await response.json();

        list.innerHTML = '';
        for (const category of categories) {
            const li = document.createElement('li');
            li.textContent = category.categoryName;
            list.appendChild(li);
        }
    } catch (error) {
        message.textContent = `Couldn't load the categories: ${error.message}`;
    }
}

async function addCategory(event) {
    event.preventDefault();

    const response = await fetch('/api/categories', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ categoryName: nameInput.value })
    });

    if (response.ok) {
        const added = await response.json();
        message.textContent = `Added ${added.categoryName}`;
        nameInput.value = '';
        await loadCategories();
    } else {
        message.textContent = `Couldn't add it: the API answered ${response.status}`;
    }
}

form.addEventListener('submit', addCategory);
loadCategories();
```

What happens:

1. The page loads, and `loadCategories()` runs straight away: it fetches the list, then builds an `li` for each category. The page appeared first, empty, and fills in a moment later.
2. Typing *Snacks* and pressing **Add** fires the form's `submit` event. `addCategory` stops the page reloading, `POST`s the new category as JSON, shows *Added Snacks*, and loads the list again, now with Snacks at the end.
3. A name longer than 15 letters gets `400` from the API's validation, and the page says *Couldn't add it: the API answered 400*.

The page never reloads: it only ever swaps in the parts that changed. That's how modern web apps feel so quick, and it's the idea Angular builds on in the next module.

(`li.textContent = ...` puts the name in as plain **text**. With `innerHTML`, a category named `<img src=x onerror=alert(1)>` would run as code on everyone's page. When the text comes from a user or an API, always use `textContent`.)

## Check yourself

2 questions to try on the lesson page.

## So what

`async` and `await` make JavaScript's waiting look like C#'s: top to bottom, with `try` and `catch`. Fetch, check, read the JSON, change the page: that loop is how every page talks to an API.

## Key terms

- [async Function](https://www.ask-codey.com/glossary/async-function)
- [await](https://www.ask-codey.com/glossary/await)

## Cheat sheets

- [Async and Await](https://www.ask-codey.com/cheat-sheets/calling-apis-from-javascript-async-and-await-cheat-sheet)

Source: https://www.ask-codey.com/lessons/calling-apis-from-javascript-async-and-await
