Skip to main content

Блокуючий і неблокуючий код

Що таке блокуючий і неблокуючий код

ТермінЩо означає
Блокуючий код (blocking code)Виконання програми зупиняється, поки операція не завершиться
Неблокуючий код (non-blocking code)Програма продовжує виконання, не чекаючи завершення операції

1. Блокуючий код

Програма чекає, поки операція (наприклад, читання файлу чи запит до БД) закінчиться, перш ніж іти далі.

Приклад (синхронне читання файлу в Node.js):

javascript
const fs = require('fs'); console.log('1. Початок'); const data = fs.readFileSync('file.txt', 'utf8'); // блокуючий виклик console.log('2. Файл прочитано'); console.log('3. Кінець');

Вивід:

javascript
1. Початок 2. Файл прочитано 3. Кінець

Поки fs.readFileSync читає файл, весь потік заблокований - Node.js не може обробити інші запити чи події.

2. Неблокуючий код

Програма не чекає - вона запускає операцію й одразу йде далі. Коли операція завершиться, результат повертається через callback, Promise або async/await.

Приклад (асинхронне читання файлу):

javascript
const fs = require('fs'); console.log('1. Початок'); fs.readFile('file.txt', 'utf8', (err, data) => { console.log('2. Файл прочитано'); }); console.log('3. Кінець');

Вивід:

javascript
1. Початок 3. Кінець 2. Файл прочитано

Тут fs.readFile виконується у фоні (через libuv), а основний потік не блокується й продовжує роботу. Коли файл готовий - callback потрапляє в чергу подій (event loop).

3. Що робить код блокуючим

Будь-яка операція, яка чекає завершення введення-виведення (I/O) в основному потоці, - блокуюча:

  • fs.readFileSync(), fs.writeFileSync()
  • JSON.parse() на величезних даних
  • складні обчислення (наприклад, цикл на мільйони ітерацій)
  • синхронні мережеві запити (якби вони були в Node.js)

Проблема:

В однопоточному Node.js одна блокуюча ділянка коду може "заморозити" весь сервер.

4. Як Node.js робить код неблокуючим

Node.js реалізує неблокуючу модель введення-виведення (non-blocking I/O) за допомогою:

  • event loop (циклу подій),
  • libuv (бібліотеки, що створює фоновий пул потоків).

Принцип:

  1. JS-код запускає операцію (наприклад, читання файлу).
  2. Вона передається в libuv → виконується в іншому потоці.
  3. Основний потік продовжує роботу.
  4. Коли операція завершена → callback/Promise потрапляє назад в event loop.

Аналогія

Уяви кав'ярню:

СценарійЩо відбувається
БлокуючийБариста бере замовлення, чекає, поки звариться кава, і лише потім приймає наступне замовлення.
НеблокуючийБариста бере замовлення, віддає його в роботу й одразу приймає наступне. Коли кава готова - просто віддає клієнту.

Результат: обслуговано більше клієнтів, ніхто не чекає марно.

5. Приклад на практиці - вебсервер

Блокуючий сервер

javascript
const http = require('http'); const fs = require('fs'); http.createServer((req, res) => { const data = fs.readFileSync('data.json'); // блокує потік! res.end(data); }).listen(3000);

Один запит "зависне" - решта чекатиме.

Неблокуючий сервер

javascript
const http = require('http'); const fs = require('fs'); http.createServer((req, res) => { fs.readFile('data.json', (err, data) => { res.end(data); }); }).listen(3000);

Сервер обробляє безліч запитів одночасно, бо читання файлів виконується у фоні.

6. Порівняння в таблиці

КритерійБлокуючий кодНеблокуючий код
Модель виконанняСинхроннаАсинхронна
Потік виконанняОдин, і він чекаєОдин, але не чекає
ПродуктивністьПовільна при I/OВисока при I/O
Підходить дляПростих скриптівСерверів, API
Приклад у Node.jsfs.readFileSync()fs.readFile()

Підсумок

  • Блокуючий код - зупиняє виконання програми, поки операція не завершиться.
  • Неблокуючий код - дозволяє виконувати інші задачі, поки операція виконується у фоні.
  • Node.js побудований навколо неблокуючого I/O й event loop, тому може обробляти тисячі запитів на одному потоці.

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

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

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