مستوى المقال: مبتدئ — لو لسه شغال على JavaScript أقل من سنة، المقال ده ليك. هتفهم بعد 8 دقايق ليه الكود اللي بتكتبه أحيانًا بيتنفذ بترتيب مش متوقع، وتعرف تتنبأ بالناتج قبل ما تشغّل السكربت.
Event Loop للمبتدئ: ليه console.log بعد setTimeout(0) بيطبع قبله
أول مرة شفت الناتج ده غالبًا اتلخبطت: setTimeout بصفر مللي ثانية، ومع ذلك السطر اللي تحته اتنفذ الأول. ده مش bug، ده اللي JavaScript بتعمله بالظبط كل ثانية. الفهم ده هيوفّر عليك ساعات debugging في الكود الـ async.
المشكلة باختصار
JavaScript بتشتغل على thread واحد بس. يعني في أي لحظة، فيه سطر كود واحد بيتنفذ. لو الـ thread ده اتشغل في عملية تاخد ثانية كاملة، الصفحة كلها بتتجمد. المتصفح ميقدرش حتى يستجيب لضغطة فأرة.
الحل اللي اخترعته JavaScript: أي عملية بتاخد وقت (طلب شبكة، قراءة ملف، مؤقّت زمني) متتنفذش على الـ thread الرئيسي. بتتأجّل في طابور انتظار، والـ thread يفضل حر. الـ Event Loop هو المسؤول عن إدارة الطابور ده.
مثال قبل ما ندخل تقني: الطاهي المنفرد
تخيل مطعم صغير فيه طاهٍ واحد بس. الطاهي ده قدامه طلبين:
- طلب فوري: ساندوتش بسيط، بياخد دقيقة، الطاهي بيعمله على طول.
- طلب مؤجّل: كيكة لازم تتسوّى في الفرن 30 دقيقة. الطاهي بيحطها في الفرن، ويعلّق تذكرة "خلصت في 8:30"، ويرجع يكمّل الطلبات التانية.
لو جالك زبون جديد طلب "كيكة، وقت طبخها صفر دقايق"، الطاهي عمره ما هياخدها على طول. ليه؟ لأنه بـ السياسة بتاعته بيكمّل الطلبات اللي قدامه دلوقتي، بعدين يبص في تذاكر الكيك الجاهز. حتى لو وقت الطبخ صفر، التذكرة لازم تعدّي على نفس الطابور.
ده بالظبط اللي setTimeout(callback, 0) بيعمله: بيقول للـ JavaScript "اعمل الكولباك ده بأقرب فرصة ممكنة، بس مش دلوقتي. خلّي السطور اللي بعده يخلصوا الأول".
التعريف العلمي بدقة
الـ JavaScript runtime (سواء V8 في المتصفح أو في Node.js) فيه ٤ مكونات شغّالة معاك دلوقتي:
- Call Stack: طابور الدوال اللي بتتنفذ حاليًا. أي سطر
console.logأو حسبة عادية بيدخل هنا، بيتنفذ، يطلع. - Web APIs / libuv: هنا بيتعالج كل اللي خارج JavaScript نفسها — المؤقتات، fetch، قراءة ملف. ده بيتشغّل في الخلفية بـ thread تاني خالص.
- Task Queue: طابور الكولباكس اللي خلّصت من الـ APIs ومستنية ترجع تتنفذ.
- Event Loop: الحلقة اللي بتسأل سؤال واحد ٢٤٠ مرة في الثانية: "الـ Call Stack فاضي؟ لو فاضي، خد أول حاجة في الـ Task Queue وحطها فيه".
القاعدة الأساسية: ده يعني إن أي كود متزامن (synchronous) بتكتبه هيخلص بالكامل قبل أي كولباك مؤجّل.