← Назад к вопросам

JS однопоточный или многопоточный

1.3 Junior🔥 181 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Однопоточность JavaScript и Event Loop

JavaScript — это однопоточный язык программирования. Это значит, что в один конкретный момент времени может выполняться только один блок кода. Однако благодаря асинхронному программированию и Event Loop, JavaScript может создавать иллюзию параллельного выполнения и эффективно работать с операциями ввода-вывода.

Однопоточная природа JavaScript

console.log('1. Начало');
console.log('2. Середина');
console.log('3. Конец');

// Вывод:
// 1. Начало
// 2. Середина
// 3. Конец

Каждая операция выполняется полностью, прежде чем начнётся следующая.

Проблема блокирования

function slowOperation() {
  let sum = 0;
  for (let i = 0; i < 10000000000; i++) {
    sum += i;
  }
  return sum;
}

console.log('Начало');
const result = slowOperation();
console.log('Результат:', result);
console.log('Конец');

Весь UI заморозится на время выполнения slowOperation().

Решение: Асинхронное программирование

Чтобы избежать блокирования, JavaScript предоставляет асинхронные механизмы:

1. Callbacks

console.log('1. Начало');

setTimeout(() => {
  console.log('3. Результат после 1000мс');
}, 1000);

console.log('2. Конец');

// Вывод:
// 1. Начало
// 2. Конец
// 3. Результат после 1000мс

2. Promises

console.log('1. Начало');

fetch('/api/users')
  .then(response => response.json())
  .then(data => console.log('3. Данные получены:', data))
  .catch(error => console.error('Ошибка:', error));

console.log('2. Запрос отправлен');

// Вывод:
// 1. Начало
// 2. Запрос отправлен
// 3. Данные получены

3. Async/Await

async function getData() {
  console.log('1. Начало');
  
  const response = await fetch('/api/users');
  const data = await response.json();
  
  console.log('3. Данные получены:', data);
}

console.log('2. Запрос отправлен');
getData();
console.log('4. Функция вызвана');

// Вывод:
// 1. Начало
// 2. Запрос отправлен
// 4. Функция вызвана
// 3. Данные получены

Event Loop: сердце асинхронности

Event Loop — это механизм, который управляет выполнением кода в JavaScript. Он постоянно проверяет:

  1. Есть ли код в Call Stack?
  2. Есть ли колбэки в Queue?
  3. Если Stack пуст, перенести из Queue в Stack
console.log('Начало');

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

Promise.resolve()
  .then(() => console.log('Promise'));

console.log('Конец');

// Вывод:
// Начало
// Конец
// Promise
// Timeout

Почему так? Потому что:

  1. Синхронный код выполняется первым
  2. Microtasks (Promise) выполняются раньше macrotasks (setTimeout)

Call Stack, Microtask Queue и Macrotask Queue

CALL STACK (Выполняемый код)
         ↓
Когда стек пуст:
         ↓
MICROTASK QUEUE
- Promise.then()
- MutationObserver
- queueMicrotask()
         ↓
Если Microtask пуста:
         ↓
MACROTASK QUEUE
- setTimeout
- setInterval
- I/O операции

Практический пример Event Loop

console.log('Script start');

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

Promise.resolve()
  .then(() => {
    console.log('Promise 1');
    setTimeout(() => {
      console.log('setTimeout inside Promise');
    }, 0);
  })
  .then(() => {
    console.log('Promise 2');
  });

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

console.log('Script end');

// Вывод:
// Script start
// Script end
// Promise 1
// Promise 2
// setTimeout 1
// setTimeout inside Promise
// setTimeout 2

Web Workers: истинная многопоточность

Для тяжёлых вычислений можно использовать Web Workers — они работают в отдельном потоке:

// main.js
const worker = new Worker('worker.js');

worker.postMessage({ numbers: [1, 2, 3, 4, 5] });

worker.onmessage = (event) => {
  console.log('Результат:', event.data);
};

// worker.js
self.onmessage = (event) => {
  const { numbers } = event.data;
  const sum = numbers.reduce((a, b) => a + b);
  self.postMessage(sum);
};

Web Worker:

  • Работает в отдельном потоке
  • Не блокирует UI
  • Подходит для тяжёлых вычислений
  • НЕ имеет доступа к DOM

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

Антипаттерн: Callback Hell

function loadData(callback) {
  fetch('/api/users').then(response => {
    response.json().then(users => {
      fetch('/api/posts').then(response => {
        response.json().then(posts => {
          callback(users, posts);
        });
      });
    });
  });
}

Правильно: Async/Await

async function loadData() {
  const usersResponse = await fetch('/api/users');
  const users = await usersResponse.json();
  
  const postsResponse = await fetch('/api/posts');
  const posts = await postsResponse.json();
  
  return { users, posts };
}

const data = await loadData();

Производительность и оптимизация

1. Параллельное выполнение

// Последовательно (медленно)
const user = await fetchUser(1);
const posts = await fetchPosts(user.id);

// Параллельно (быстро)
const user = await fetchUser(1);
const [posts, comments] = await Promise.all([
  fetchPosts(user.id),
  fetchComments(user.id)
]);

2. Обработка ошибок

async function safeOperation() {
  try {
    const response = await fetch('/api/data');
    if (!response.ok) throw new Error('API error');
    return await response.json();
  } catch (error) {
    console.error('Ошибка:', error);
    throw error;
  } finally {
    console.log('Операция завершена');
  }
}

Ключевые концепции

  1. JavaScript однопоточный — только один код выполняется одновременно
  2. Event Loop — управляет порядком выполнения кода
  3. Асинхронные операции — не блокируют UI, используют callbacks/promises
  4. Microtasks vs Macrotasks — Promises выполняются раньше setTimeout
  5. Web Workers — для истинного параллелизма
  6. Async/await — современный способ работы

Типичный ответ на интервью

"JavaScript — однопоточный язык. Только один блок кода выполняется одновременно. Однако благодаря Event Loop и асинхронному программированию, мы можем обрабатывать множество операций без блокирования UI. Для истинного параллелизма в тяжёлых вычислениях используются Web Workers."

Это показывает глубокое понимание как языка, так и практики веб-разработки.

JS однопоточный или многопоточный | PrepBro