لو endpoint بسيط في تطبيقك بياخد 4 ثواني يرد، وفتحت htop ولقيت CPU 30% بس، Node.js مش بطيء وسيرفرك مش متخوم. فيه سطر واحد جوّا الـ request handler بيقفل الـ event loop ومحدش يقدر يرد على أي طلب تاني لحد ما يخلّص. المقال ده بيوريك ازاي تكتشف العملية دي بـ perf_hooks وتنقلها لـ Worker Thread في 30 سطر.
Event Loop في Node.js: المشكلة الحقيقية ورا التجمّد
المشكلة باختصار
Node.js بيشغّل JavaScript على thread واحد. لمّا الـ thread ده بياخد عملية CPU-heavy (توقيع PDF، parse JSON كبير، bcrypt بـ rounds عالية، regex معقّد) كل الـ requests التانية بتستنّى في طابور. الـ CPU مش بيوصل 100% لأن core واحد فقط شغّال — والباقي قاعد. ده اللي بيخلّي السيرفر يبان "متجمّد" مع إن المراقبة بتقول إنه فاضي.
مثال المخبز — يفهمه أي مبتدئ
تخيّل مخبز فيه فرّان واحد بس. الزبون الأول طلب كرواسون (دقيقتين). الفرّان قعد يفرد العجين بإيده. خلال الدقيقتين دول، 12 زبون دخلوا وكل واحد عايز قهوة (10 ثواني بس). محدش هيتخدم. الفرّان مش كسلان، هو شغّال — بس على مهمة واحدة طويلة قفلت "نظام الخدمة" كله.
Node.js نفس الفكرة. الـ event loop هو نظام الخدمة. اللحظة اللي تشغّل فيها JSON.parse على ملف 18 ميجا، الـ thread اللي بيخدم كل الزباين قاعد بيقرأ الـ JSON. أي طلب تاني بيستنى في الطابور، حتى لو هو طلب بسيط مثل /health.
التعريف العلمي — Event Loop و libuv
Node.js مبني على V8 (لتشغيل JavaScript) و libuv (للـ I/O غير المتزامن). الـ event loop هو حلقة في libuv بتتنقل بين 6 phases: timers، pending callbacks، idle/prepare، poll، check، close callbacks. كل phase فيها queue من الـ callbacks الجاهزة للتنفيذ. JavaScript بيشتغل في مرحلة منهم بشكل synchronous.
الافتراض الأساسي: لازم كل callback تخلّص بسرعة (≤ 10ms كقاعدة). لو callback أخدت 200ms، كل الـ phases التانية وكل الـ I/O callbacks اللي وصلت من kernel استنّت 200ms. بالظبط زي ما توثيق Node.js الرسمي بيقول: "you cannot fix what you cannot see"، فأول خطوة هي القياس.
libuv كمان فيه thread pool مساعد بـ 4 threads افتراضيًا (يتغير عبر UV_THREADPOOL_SIZE). الـ pool ده بيستخدمه fs و crypto.pbkdf2 و zlib. لكن — ركز هنا — أي JavaScript بتكتبه إنت بيتنفّذ على main thread، مش على الـ thread pool. ده مصدر اللخبطة الأكبر.
ازاي تقيس Event Loop Delay فعلاً
الطريقة الشائعة الغلط: تشغّل setInterval وتقيس الفرق. ده بيخفي 90% من الحقيقة. الطريقة الصح من توثيق Node.js: perf_hooks.monitorEventLoopDelay().