المستوى: متوسط. المقال ده لأي حد كتب جافاسكريبت وبيستخدم setTimeout وPromise، بس لسه مش فاهم ليه الكود بيطلع بترتيب غير اللي كتبه. مش محتاج تكون خبير، بس محتاج تعرف الدوال والوعود (Promises).
لو setTimeout(fn, 0) عندك بيشتغل بعد كود كتبته تحته، ده مش باج ولا بطء في المتصفح. ده تصميم مقصود اسمه الـ Event Loop، ولما تفهمه هتوقف تخمين وتبقى تعرف بالظبط أي كود هيجري الأول.
الـ Event Loop في جافاسكريبت: ليه setTimeout بصفر بيشتغل في الآخر
المشكلة باختصار
جافاسكريبت لغة بخيط واحد (single-threaded). يعني في أي لحظة بتنفّذ سطر واحد بس. لكن المتصفح بيعمل حاجات كتير في نفس الوقت: بيحمّل صور، بيستنى ردود شبكة، بيسمع نقرات الفأرة. السؤال: إزاي لغة بخيط واحد بتتعامل مع كل ده من غير ما تتجمّد؟ الجواب هو الـ Event Loop. وسوء فهمه بيسبب أشهر أنواع الباجات: كود بيجري بترتيب غير متوقّع، وواجهة بتتجمّد فجأة.
مثال قبل النظرية: مطعم بطبّاخ واحد
تخيّل مطعم فيه طبّاخ واحد بس (ده الـ CPU thread بتاعك). قدّامه منضدة صغيرة بيحضّر عليها طلب واحد في المرة (ده الـ Call Stack). الطلبات الجاهزة للطبخ بتتحط في طابور على الشباك (ده Task Queue).
لكن في قاعدة صارمة في المطبخ ده: قبل ما الطبّاخ يبدأ أي طلب جديد من الطابور الكبير، بيبص الأول على "ورقة الملاحظات العاجلة" جنبه، وبينفّذ كل اللي فيها بالكامل. الورقة العاجلة دي هي الـ Microtask Queue. الوعود (Promises) بتكتب فيها. عشان كده الوعد بيتنفّذ قبل الـ setTimeout حتى لو الاتنين "جاهزين"، وحتى لو الـ timeout مكتوب فوقه في الكود.
دلوقتي المثال خلص، نرجع للتعريف العلمي الدقيق.
تفكيك المكوّنات علميًا
- Call Stack: مكدس بيشتغل بمبدأ LIFO (آخر داخل أول خارج). كل استدعاء دالة بيتحط فوق، ولما يخلّص بيتشال. طول ما فيه حاجة على المكدس، الـ Event Loop مبيعملش أي حاجة تانية.
- Web APIs: مش جزء من محرّك جافاسكريبت. دي قدرات بيوفّرها المتصفح (أو Node): المؤقّتات،
fetch، أحداث الـ DOM. لما تناديsetTimeout، المتصفح هو اللي بيعدّ الوقت، مش الـ thread بتاعك. - Macrotask Queue: طابور فيه المهام "الكبيرة": callbacks بتاعة
setTimeoutوsetInterval، أحداث الـ I/O، ورسم الواجهة. الـ Event Loop بياخد مهمة واحدة بس من هنا في كل لفّة. - Microtask Queue: طابور أعلى أولوية. فيه
Promise.then/catch/finally، ، و. القاعدة الذهبية: بعد كل مهمة كبيرة، الـ Event Loop بيفضّي طابور المهام الدقيقة قبل ما ياخد المهمة الكبيرة اللي بعدها أو يرسم الشاشة.