Course content
50 min

Make Asynchronous States Visible

Represent loading, ready, empty and error without hiding uncertainty

By the end of this lesson

  • Model distinct asynchronous outcomes
  • Use Console and Network evidence to locate loading failures

items alone cannot tell the full story

When state.items is empty, the application may still be loading, may have loaded zero records or may have failed. Add an explicit status.

Imagine seeing an empty shop shelf. You cannot know whether delivery is still coming, the delivery contained nothing or the truck failed to arrive. The list alone does not explain the situation. status supplies the missing meaning.

const state = {
  items: [],
  search: '',
  topic: 'all',
  availableOnly: false,
  selectedId: null,
  status: 'not-started',
  error: null
};

Use a small, deliberate set of status values:

not-started -> loading -> ready
                       -> empty
                       -> error
  • not-started: loading has not started.
  • loading: the application is waiting.
  • ready: one or more items arrived.
  • empty: loading succeeded but returned zero items.
  • error: loading did not produce a usable result.

Show the transition in init

async function init() {
  connectEvents();
  state.status = 'loading';
  render();

  try {
    state.items = await fetchResources();
    state.status = state.items.length === 0 ? 'empty' : 'ready';
  } catch (error) {
    state.status = 'error';
    state.error = error instanceof Error ? error.message : 'Unknown error';
  }

  render();
}

The first render shows loading immediately. The second render shows the outcome. An error remains distinct from a valid empty result.

Render each state deliberately

function render() {
  renderStatus(state.status, state.error);

  if (state.status === 'ready') {
    renderResources(getVisibleItems());
  } else {
    renderResources([]);
  }
}

You may decide to keep old items visible during a refresh, but make that product decision explicit. Do not let accidental stale content communicate success.

Debug data loading with evidence

Use browser developer tools in this order:

  1. Network: Was a request sent to the intended URL?
  2. Status: Was the response 200, 404, 500 or another value?
  3. Response: Is the body valid JSON with the expected shape?
  4. Console: Did parsing, validation or rendering throw an error?
  5. State: After awaiting, what are status, items and error?

Open the HTML through a local web server. Opening it directly as a file can produce browser restrictions and paths that behave differently from HTTP.

Controlled failure

Temporarily change the URL to /data/missing.json. Predict the transitions, inspect the Network panel, and verify that the interface leaves loading and shows an error. Restore the correct path afterward.

Say the observed path aloud: "not-started, then loading, then error." Naming the transition is more useful than memorizing the catch block.

What to remember

Loading, empty and error are different facts. Represent them in state, render them intentionally and debug from network evidence toward state and DOM.

Lesson complete?

Your progress is saved on this device.