HomebaseWorks
Lesson 2 of 4

Promises, async/await and the event loop

Why asynchronous code logs in the order it does, and how to write and handle promises and async functions safely.

EWritten by the HomebaseWorks editorial team · reviewed 26 Oct 2026

JavaScript runs your code on a single thread. Asynchronous work such as timers and network requests is handed off, and its callbacks are queued to run later. Questions about output order are really questions about those queues.

Advertisement

The order of execution

  1. All synchronous code in the current script runs first, top to bottom.
  2. Then the microtask queue is emptied. Callbacks from then and catch, and code after an await, go here.
  3. Then one task from the task queue runs, such as a setTimeout callback, and the cycle repeats.
console.log("start");
setTimeout(() => console.log("timeout"), 0);
Promise.resolve().then(() => console.log("promise"));
console.log("end");
// start, end, promise, timeout

A delay of 0 does not mean immediately. It means as soon as the call stack is empty and the microtasks are done.

Promises

A promise starts as pending, then is either fulfilled with a value or rejected with a reason. Chain then for results and end with catch for errors. Promise.all waits for every promise and rejects as soon as any one rejects, while Promise.allSettled waits for all of them and reports each outcome.

async and await

An async function always returns a promise. If it returns 5, the caller receives a promise that resolves to 5. Inside it, await pauses that function until the promise settles, without blocking the rest of the page.

async function loadUser(id) {
  try {
    const res = await fetch("/api/users/" + id);
    if (!res.ok) throw new Error("HTTP " + res.status);
    return await res.json();
  } catch (err) {
    console.error("Could not load user", err);
    return null;
  }
}

Two mistakes come up often. Forgetting await leaves you holding a promise instead of data, and awaiting independent requests one by one is slower than running them together with Promise.all.

Habit to build

When you see a snippet with timers and promises, label each line as sync, microtask or task, then write the output in that order. It takes a few seconds and removes the guesswork.

Advertisement
Continue with JavaScript4 lessons · 1 interview set · 1 test · 1 certificate
Not tested

More in Programming