Event loop w Node.js jest sercem asynchronicznego modelu wykonania. Dzięki jednowątkowemu podejściu pozwala na obsługę setek tysięcy jednoczesnych połączeń, ale tylko pod warunkiem, że kod nie blokuje wątku. W tym artykule przyjrzymy się, jak działa event loop w Node.js, jakie problemy najczęściej pojawiają się w środowiskach produkcyjnych oraz jakie techniki można zastosować, aby utrzymać wysoką przepustowość.
Budowa i fazy event loop
Node.js opiera się na libuv, bibliotece C, która implementuje czterostopniowy event loop. Fazy obejmują timers, pending callbacks, idle, prepare, poll, check oraz close callbacks. Każda faza posiada własną kolejkę zadań; po jej zakończeniu przechodzi się do następnej. Dlatego rozumienie, w której fazie trafiają konkretne operacje, jest kluczowe dla optymalizacji.
Dlaczego blokowanie wątku niszczy wydajność
Node.js jest jednowątkowy pod względem JavaScriptu. Jeśli w kodzie pojawi się operacja CPU‑intensywna – np. pętla while(true) lub kosztowna serializacja JSON – zajmuje ona cały cykl event loop i uniemożliwia obsługę kolejnych zdarzeń. Efekt to zwiększone opóźnienia (latencja) i spadek liczby obsłużonych żądań na sekundę.
// przykład blokującej pętli
while (true) {
// symulacja ciężkiego obliczenia
const now = Date.now();
if (now % 1000000 === 0) break;
}
W praktyce takie fragmenty pojawiają się nieświadomie – np. przy nieoptymalnym sortowaniu dużych tablic lub synchronizacji IO (fs.readFileSync). Dlatego każde wywołanie synchroniczne w kodzie produkcyjnym powinno być dokładnie przemyślane.
Monitorowanie event loop w Node.js
Do obserwacji stanu pętli najczęściej używa się wbudowanego modułu perf_hooks oraz narzędzia clinic. perf_hooks.monitorEventLoopDelay() zwraca statystyki opóźnień, które można zapisać do Prometheusa lub logów.
const { monitorEventLoopDelay } = require('perf_hooks');
const h = monitorEventLoopDelay({ resolution: 20 });
h.enable();
setInterval(() => {
console.log(`p95: ${h.percentile(95)}ms`);
}, 5000);
Regularne monitorowanie pozwala wykryć nagłe skoki latency, które najczęściej są wynikiem blokowania wątku lub niewydajnych operacji I/O.
Kiedy używać async/await, a kiedy pozostać przy strumieniach
Async/await upraszcza kod, ale wprowadza dodatkowy mikro‑task po każdej operacji await. W scenariuszach, gdzie przetwarzane są setki tysięcy małych żądań, narzut ten może być zauważalny. Alternatywą są strumienie (Readable, Writable) i metoda .pipe(), które pozwalają na przetwarzanie danych w trybie back‑pressure, minimalizując liczbę mikro‑tasków.
// przetwarzanie dużego pliku przy użyciu strumieni
const fs = require('fs');
const zlib = require('zlib');
fs.createReadStream('big.log')
.pipe(zlib.createGzip())
.pipe(fs.createWriteStream('big.log.gz'));
Strumienie są więc lepszym wyborem, gdy zależy nam na stałej przepustowości i kontrolowanym zużyciu pamięci.
Typowe pułapki wydajnościowe i ich eliminacja
- Synchronizacja IO – zamień
fs.readFileSyncnafs.promises.readFilelub strumienie. - Nieoptymalne algorytmy – zamień O(n²) sortowanie na
Array.prototype.sortlub biblioteki C++ (np.fast-sort). - Zbyt duże obiekty w pamięci – używaj
BufferiTypedArrayzamiast stringów przy przetwarzaniu binarnym. - Brak ograniczeń concurrency – wprowadź pool workerów (
worker_threads) lub limit kolejki (p‑limit).
„Event loop nie jest magiczną puszką – to mechanizm, który wymaga świadomego projektowania, aby nie stał się wąskim gardłem.”
Praktyczny checklist: optymalizacja event loop
- Używaj asynchronicznych API wszędzie, gdzie to możliwe.
- Profiluj kod z
clinic doctori analizuj wykresy event loop. - Wprowadzaj limit równoczesnych operacji I/O (np.
p-limit). - Rozważ delegowanie ciężkich obliczeń do workerów lub usług zewnętrznych.
- Monitoruj
perf_hooks.monitorEventLoopDelayi ustaw alerty na p95 > 30 ms.
Podsumowanie i zaproszenie do współpracy
Rozumienie, jak działa event loop w Node.js, oraz świadome unikanie blokujących operacji to podstawa budowania skalowalnych usług. Dzięki regularnemu monitorowaniu, profilowaniu i zastosowaniu opisanych technik możesz znacząco podnieść wydajność swoich aplikacji. Jeśli potrzebujesz wsparcia w audycie wydajności, optymalizacji kodu lub budowie architektury opartej na Node.js, zespół Coderia.it jest gotowy pomóc – napisz do nas i wspólnie podnieśmy Twoje systemy na wyższy poziom.



