CohortX
Блог

Asynchrony in JavaScript: understanding it once and for all

2 августа 2026 г. · 3 мин чтения · Читать по-русски · Антон Молотило

What the problem is

Ordinary code runs top to bottom. Asynchronous code doesn't.

console.log("one");
setTimeout(() => console.log("two"), 0);
console.log("three");

Prints: one, three, two. Even with a zero delay.

Understanding why is half the topic.

Why it happens

The browser has a single thread of execution: it does one thing at a time and can't wait. If a request to a server halted execution, the page would freeze for seconds.

So long operations work differently: you say "do this and call me when it's done", and execution continues. When the operation completes, your handler joins a queue and runs as soon as the thread is free.

Hence the rule: anything involving waiting joins a queue and runs later than the ordinary code that follows it.

The first approach: callbacks

Historically first: you pass a function to be called when ready.

The problem is well known: with several operations chained, nesting grows and the code becomes a staircase nobody can read.

The second approach: promises

A promise is an object representing a result you don't have yet. It has three states: pending, fulfilled, rejected.

fetch("/api/notes")
  .then((res) => res.json())
  .then((data) => console.log(data))
  .catch((err) => console.error(err));

It reads top to bottom: made the request, then parsed the response, then used it; an error anywhere in the chain lands in the error handler.

The third approach: await

The modern syntax, with the same machinery behind it:

async function loadNotes() {
  try {
    const res = await fetch("/api/notes");
    const data = await res.json();
    console.log(data);
  } catch (err) {
    console.error(err);
  }
}

Here the code looks sequential again. The await keyword says: "stop here until there's a result, but don't block everything else".

Two rules:

  • Await works only inside a function marked as asynchronous.
  • Such a function always returns a promise, even when the body returns an ordinary value.

Common mistakes

Forgetting to await. The function was called but the result wasn't awaited — you get a promise instead of data.

Awaiting in a loop when the operations are independent. Five requests one after another instead of together. If order doesn't matter, start them together and await them all at once.

No error handling. A failed request without a catch produces a cryptic console error and leaves the interface hanging.

Awaiting inside an array iteration helper. A classic: ordinary iteration can't wait, and the code moves on regardless.

Checking that you understood

Answer this: why does "two" print last in the opening example, despite a zero delay? If you can explain it in words about the queue and the thread being freed, the topic is closed.

Then practise: build a page making three requests — two independent ones together and a third after them — with error handling and a loading state.

Хватит читать — пора делать

На CohortX можно найти команду под пет-проект и получить тот самый опыт, о котором спрашивают на собеседовании.

Похожие статьи