Skip to main content

Черга задач (task queue)

Черга задач (Task Queue) це структура даних, у якій зберігаються задачі (колбеки), що очікують на виконання після звільнення стека викликів (Call Stack). Вона є ключовим елементом механізму Event Loop (циклу подій) у JavaScript.

Теорія

TL;DR

  • Черга задач зберігає колбеки, які вже готові виконатися, але чекають, доки звільниться стек викликів.
  • JavaScript однопотоковий, тому одночасно виконується лише одна задача.
  • Event Loop бере першу задачу з черги (FIFO) і кладе її у стек, щойно стек стає порожнім.
  • Черг насправді дві: черга макрозадач (setTimeout, події DOM) і черга мікрозадач (Promise.then, queueMicrotask).
  • Мікрозадачі завжди виконуються раніше за наступну макрозадачу.
  • Порядок такий: стек, потім мікрозадачі, потім макрозадачі.

Швидкий приклад

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

Вивід у консолі:

text
1 3 2

Ключова ідея

JavaScript це однопотокова мова, вона може виконувати лише одну задачу за раз. Коли рушій зайнятий виконанням функцій у стеку викликів, решта задач, наприклад обробники кліків, setTimeout, мережеві колбеки і таке інше, чекають своєї черги у черзі задач (task queue).

Коли стек викликів стає порожнім, Event Loop бере першу задачу з черги і поміщає її у стек. І так по колу, нескінченно.

Покроковий розбір прикладу

  1. console.log('1') виконується одразу і друкує 1.
  2. setTimeout(...): браузер ставить таймер. Після спрацювання таймера колбек потрапляє у чергу задач, а не виконується миттєво.
  3. console.log('3') виконується і друкує 3.
  4. Коли стек викликів порожній, Event Loop бере задачу з черги (колбек із setTimeout) і поміщає її у стек, що друкує 2.

Саме тому нульова затримка в setTimeout означає «якнайшвидше після звільнення стека», а не «негайно».

Черга задач проти черги мікрозадач

У JavaScript є дві черги:

Тип чергиДжерело задачКоли виконуються
Task Queue (macro tasks)setTimeout, setInterval, події DOM, колбеки введення/виведення і таке іншеПісля очищення стека і всіх мікрозадач
Microtask QueuePromise.then, queueMicrotask, MutationObserverОдразу після поточної задачі, до наступної макрозадачі

Різниця принципова: черга мікрозадач вичерпується повністю, а з черги макрозадач за один оберт циклу береться лише одна задача.

Приклад з мікрозадачами

javascript
console.log('A'); setTimeout(() => console.log('B'), 0); Promise.resolve().then(() => console.log('C')); console.log('D');

Порядок виводу:

text
A D C B

Пояснення:

  • A, D виконуються одразу, це синхронний код у стеку викликів.
  • C це мікрозадача, вона виконується одразу після очищення стека.
  • B це макрозадача, вона виконується після всіх мікрозадач.

Коротко про терміни

ТермінОпис
Task QueueЧерга макрозадач, зберігає колбеки від setTimeout, подій і таке інше
Microtask QueueЧерга мікрозадач, для Promise.then, queueMicrotask
Event LoopМеханізм, що стежить за стеком і чергами та вирішує, що виконувати далі
ПорядокСпочатку стек, потім мікрозадачі, потім макрозадачі

Типові помилки

  • Вважати, що setTimeout(fn, 0) виконає fn негайно. Колбек лише стає в чергу задач і чекає, доки стек спорожніє.
  • Плутати чергу задач зі стеком викликів. Стек це LIFO і те, що виконується зараз; черга це FIFO і те, що виконуватиметься потім.
  • Ставити промиси і таймери в один ряд. Promise.then іде в чергу мікрозадач і завжди випередить будь-який setTimeout, навіть з нульовою затримкою.
  • Нескінченно породжувати мікрозадачі. Якщо мікрозадача щоразу додає нову мікрозадачу, черга ніколи не спорожніє і макрозадачі та рендеринг просто не отримають керування.
  • Думати, що черга робить код паралельним. Усе одно виконання проходить через один потік і один стек, просто в іншому порядку.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.