Перед тем как разбираться в асинхронности, классах и архитектуре, важно понять одну вещь: JavaScript выполняет код строго по шагам, и большинство «странных» ситуаций в коде объясняются именно порядком выполнения.

Начнём с самого простого примера и будем постепенно его расширять.

Простейший пример выполнения кода

console.log('A');
console.log('B');
console.log('C');

Результат:

A 
B 
C

Здесь всё очевидно: JavaScript читает файл сверху вниз и выполняет инструкции по очереди.

Это и есть синхронное выполнение — следующая строка начинает выполняться только после завершения предыдущей.

Что значит «код выполняется»

Когда JavaScript «выполняет код», он:

  1. Читает инструкцию
  2. Выполняет её
  3. Переходит к следующей

Если инструкция простая (вывод в консоль, присваивание переменной), переход происходит сразу.

Добавим переменные:

const a = 5;
const b = 10;
const sum = a + b;

console.log(sum);

JavaScript:

  • создаёт переменные
  • вычисляет выражение
  • выводит результат

Ничего параллельного здесь не происходит.

Функции не выполняются сами по себе

Рассмотрим пример с функцией:

function sayHello() {
  console.log('Hello');
}

console.log('Before');
sayHello();
console.log('After');

Результат:

Before
Hello
After

Важно понимать:

  • объявление функции не запускает её
  • код внутри функции выполняется только в момент вызова

JavaScript доходит до sayHello() и временно переключается на выполнение тела функции, а затем возвращается обратно.

Что происходит при ошибке

console.log('Start');
notDefinedFunction();
console.log('End');

Результат:

Start
Uncaught ReferenceError

JavaScript:

  • выполнил первую строку
  • дошёл до ошибки
  • остановил выполнение всего скрипта

Это важно: одна ошибка может полностью прервать выполнение кода, если она не обработана.

Появляется асинхронность

Теперь добавим setTimeout:

console.log('A');

setTimeout(() => {
  console.log('B');
}, 1000);

console.log('C');

Ожидаемый результат для новичка часто такой:

A
(пауза)
B
C

Но реальный результат:

A
C
(пауза)
B

Почему так происходит?

Почему setTimeout не блокирует код

JavaScript не ждёт выполнения setTimeout.

Когда интерпретатор доходит до этой строки, он:

  1. Регистрирует таймер
  2. Передаёт функцию «на потом»
  3. Сразу идёт дальше

Для JavaScript это означает:
«Выполнить этот код позже, когда будет возможность».

Поэтому console.log('C') выполняется сразу.

Главное правило выполнения JavaScript-кода

JavaScript выполняет одну задачу за раз и не ждёт асинхронные операции

Асинхронные операции:

  • таймеры
  • сетевые запросы
  • ожидание файлов
  • промисы

не блокируют основной поток выполнения.

Расширим пример

console.log('Start');

setTimeout(() => {
  console.log('Timeout 1');
}, 0);

setTimeout(() => {
  console.log('Timeout 2');
}, 0);

console.log('End');

Результат:

Start
End
Timeout 1
Timeout 2

Даже с задержкой 0:

  • таймеры выполняются после основного кода
  • порядок выполнения сохраняется

Почему это важно для реального кода

Понимание порядка выполнения помогает:

  • избегать ошибок с асинхронным кодом
  • правильно писать обработчики событий
  • понимать, почему данные ещё не готовы
  • не использовать «костыли» с таймерами

Пример типичной ошибки:

let data;

setTimeout(() => {
  data = 'Loaded';
}, 1000);

console.log(data); // undefined

Причина не в переменной, а в порядке выполнения.

Промежуточный вывод

На этом этапе достаточно запомнить три вещи:

  1. JavaScript выполняет код последовательно
  2. Функции выполняются только при вызове
  3. Асинхронные операции выполняются позже, не блокируя основной код

Пока важно закрепить главное: если код выглядит «странно», почти всегда причина в порядке его выполнения.