Виконання певних операцій в програмуванні може бути блокуючим, або неблокуючим.
Блокуючі операції призупиняють виконання коду в потічку, тому якщо нам потрібно виконувати декілька таких операцій, наприклад, прийняти дані через інтернет від кількох користувачів, то продуктивність роботи серверу буде дуже низькою, адже поки він обробляє дані від одного користувача, решта даних повинна чекати.
Аби пофіксити це, люди вигадали дуже просте рішення - а давайте будемо створювати по потічку на кожного користувача/ресурс, тоді операції, що стосуються окремих користувачів будуть виконуватись в окремих потічках, паралельно, і не будуть блокувати одне одного.
Такий підхід працює, але блокуючі операції можуть займати дуже багато часу, і під час цього часу нічого не відбувається, тому виходить так, що кожен потічок за всю тривалість свого життя може дуже багато часу просто стояти без діла, і в ньому нічого не відбуватиметься, але при цьому кожен потічок вимагає значних ресурсів, як от оперативної пам'яті, тому з таким підходом дуже багато ресурсів використовується на простоювання.
Яке наступне можливе рішення? - Перевірка статуса ресурсу!
Уявімо собі, що кожен ресурс, на котрому виконується блокуюча операція (таким ресурсом може бути сокет, якщо ми зчитуємо дані передані через інтернет, або файл, з котрого ми намагаємось прочитати дані) - має певну інформацію про те, що з ним зараз відбувається. Наприклад, коли дані були отримані, і сокет вже може їх повернути, то одне з полів всередині сокету, наприклад, STATUS, буде мати певне значення, котре повідомляє нас, що ми можемо прочитати дані.
Тепер, якщо в нас є декілька таких сокетів, то ми можемо створити вічний цикл, котрий перевіряв би значення поля STATUS в кожному сокеті, і якщо це поле повідомляє нас про те, що ми можемо прочитати дані - то ми їх читаємо і обробляємо, після чого цикл продовджується.
Плюсом такого підходу є те, що нам потрібен лише один потічок, в котрому крутився б цей цикл, але мінусом є те, що весь той час, коли дані не є готовими для читання, цей цикл все одно працює, перевіряючи поле STATUS кожного ресурса, а це забирає потужності процесора, і виходить так, що процесор працює, але більшість часу він нічого корисного не робить...
І тепер ми наблизились до того, як подібні речі працюють в NodeJs.
Ми й досі використовуємо один потічок, але також ми використовуємо систему подій, або ж повідомлень.
Справа в тому, що в сучасних операційних системах є можливість очікування певних подій, що відбуваються "на" ресурсах. Наприклад, коли дані готові для прочитання з сокету, або файлу на диску, то операційна система створює повідомлення про цю подію, і заносить його в певну чергу.
NodeJs може звернутись до операційної системи, аби та повернула ті повідомлення (що вже є в черзі) (при цьому повернуті повідомлення видаляються з черги, тому NodeJs завжди отримуватиме свіжі повідомлення).
Сама операція отримання цих повідомлень є блокуючою, тобто, коли ми просимо ОС повернути нам інформацію про повідомлення з черги, то код зупиняється доти, доки ОС не поверне цю інформацію, і тільки після цього код продовжить працювати.
Коли інформація про повідомлення отримана, то ми просто обробляємо її, і коли обробка закінчилась, то ми знову просимо ОС повернути нам інформацію, вже про нові повідомлення.
Псевдокод може виглядати ось так
while (events = OS.pleaseGiveEvents()) { // блокуюча операція
forEach(event in events) { // проходимось по масиву з повідомленнями
handleEvent(event); // і обробляємо кожне повідомлення
}
}
Тепер, допоки ОС не поверне нам інформацію про події/повідомлення - наш код нічого не робить (і не навантажує процесор), але як тільки нові повідомлення з'являються, то усі вони швиденько обробляються. Все це відбувається в одному потоці.
Подібна обробка повідомлень/подій називається event demultiplexing - демультиплексія подій, суть її в тому, що ми отримуємо повідомлення з різних місць (різних ресурсів), але обробляємо їх в одному місці.
А патерн проектування, що використовує цю фічу, називається Реактор. https://en.wikipedia.org/wiki/Reactor_pattern
А в NodeJs ця фіча називається event loop (але то всьо спрощено, звісно ж).