المستوى: متوسط — هذا المقال موجّه لمن كتب JavaScript لأكثر من ستة شهور ويعرف الـ Promises، لكن لم يفتح بعد الصندوق الأسود لما يحدث عندما تكتب setTimeout(fn, 0).
لو سكربت Node.js عندك بيستخدم setTimeout(fn, 0) ظنًا منك أن الدالة هتشتغل فورًا، أنت بتدفع تأخير حقيقي قدره 1ms على الأقل، وبيوصل لـ 4.1ms في الـ P95. الـ Promise.resolve().then(fn) بيشتغل في 0.04ms على نفس السيرفر. الفرق مش عشوائي ومش بسبب الـ CPU. الفرق إن الاتنين بيدخلوا في طابورين مختلفين كليًا داخل الـ Event Loop.
Event Loop في Node.js: ليه ترتيب التنفيذ مش زي ما بتتوقّع
المشكلة باختصار
كتير من المطورين بيستخدموا setTimeout(fn, 0) كأداة "أجِّل التنفيذ شوية" بدون ما يعرفوا الفرق بينه وبين process.nextTick و queueMicrotask و setImmediate. النتيجة: bugs غريبة في الترتيب، latency مرتفع بدون سبب واضح، و race conditions صعبة الإعادة. الحل مش في تجنّبها — الحل في فهم الطابور اللي كل واحدة منهم بتدخله.
مثال طابور المطار (للمبتدئ المطلق)
تخيّل مطار فيه أربع كاونترات بترتيب ثابت: تذاكر، شنط، جوازات، بوّابة. الراكب لازم يمشي عليهم بالترتيب ده دايمًا. كل دورة كاملة على الأربعة اسمها "tick". لو واحد ادّاك ورقة قبل ما تخلّص الكاونتر اللي أنت فيه دلوقتي، أنت ملزوم تقرأها قبل ما تخطو للكاونتر اللي بعده — حتى لو فيه طابور مستنّيك في الكاونتر التاني. الورقة دي اسمها microtask.
الـ Event Loop في Node.js بيشتغل بنفس المنطق بالظبط. كل دورة فيها مراحل (phases) ثابتة الترتيب، وبين أي مرحلتين بيتنفّذ كل الـ microtasks المتراكمة قبل ما ينتقل.
التعريف العلمي الدقيق
الـ Event Loop في Node.js مبني على مكتبة libuv، وبيتكوّن من ست مراحل أساسية بترتيب ثابت في كل tick: timers (بتنفّذ callbacks الـ setTimeout و setInterval اللي وصل ميعادها)، pending callbacks، idle/prepare (داخلي)، poll (بيستنّى I/O)، check (بتنفّذ setImmediate)، و close callbacks. بين أي مرحلتين، ينفّذ Node طابور process.nextTick أولاً ثم طابور الـ Promise microtasks (queueMicrotask والـ .then) حتى يفرغا تمامًا.
المعنى العملي: الـ microtask اللي اتزرعت أثناء تنفيذ أي callback هتشتغل قبل أي callback تاني من أي phase. أما setTimeout(fn, 0) فهي بتدخل طابور timers، وفي أحسن الأحوال هتستنّى دورة Event Loop كاملة قبل ما تتنفّذ.