ما الذي تعتقد أنه سيحدث إذا قمت بتشغيل هذا الرمز في وحدة تحكم المتصفح؟
function foo() { setTimeout(foo, 0); } foo();
وهذا واحد؟
function foo() { Promise.resolve().then(foo); } foo();
إذا كنت ، مثلي ، قد قرأت مجموعة من المقالات حول Event Loop ، و Main Thread ، والمهام ، و microtasks وغيرها ، ولكن تجد صعوبة في الإجابة على الأسئلة أعلاه - هذه المقالة لك.
لذلك دعونا نبدأ. يتم تنفيذ التعليمات البرمجية لكل صفحة HTML في المستعرض في
الخيط الرئيسي . الخيط الرئيسي هو الخيط الرئيسي حيث ينفذ المتصفح JS ، يعيد رسم ، يعالج إجراءات المستخدم ، وأكثر من ذلك بكثير. في الأساس ، هذا هو المكان الذي يتم فيه دمج محرك JS في المتصفح.
أسهل طريقة لمعرفة ذلك هي النظر إلى المخطط:
الشكل 1نرى أن المكان الوحيد الذي يمكن من خلاله الوصول إلى Call Stack وإكماله هو Event Loop. تخيل أنك كنت في مكانه. عملك هو مواكبة المهام. يمكن أن تكون المهام من نوعين:
- شخصي - تنفيذ شفرة JavaScript الرئيسية على الموقع (فيما يلي سنفترض أنه قد تم تنفيذها بالفعل)
- مهام العميل - التجسيد ، المهام الدقيقة ، والمهام
على الأرجح ، سيتم تحديد أولويات مهامك الشخصية. يوافق Event Loop على هذا :) يبقى لتبسيط المهام من العميل.
بطبيعة الحال ، فإن أول ما يتبادر إلى الذهن هو إعطاء كل عميل أولوية ، وتنسيقها. والثاني هو تحديد بالضبط كيفية معالجة المهام من كل عميل - واحدة في وقت واحد ، دفعة واحدة ، أو ربما على دفعات.
ألق نظرة على هذا المخطط:
الشكل 2بناءً على هذا المخطط ، تم تصميم العمل الكامل لـ Event Loop.
بعد أن بدأنا في تنفيذ أي برنامج نصي ، يتم وضع مهمة تنفيذ هذا البرنامج النصي في قائمة انتظار المهام. عند تنفيذ هذا الرمز ، نواجه مهام من عملاء مختلفين ، يتم وضعها في قائمة الانتظار المناسبة. بعد اكتمال مهمة تنفيذ البرنامج النصي (المهمة من المهام) ، تنتقل حلقة الأحداث إلى المهام الصغيرة (بعد المهمة من المهام ، تأخذ حلقة الأحداث مهام من المهام الصغيرة). يأخذ الحدث حلقة المهام منه
حتى تنتهي . هذا يعني أنه إذا كان وقت الإضافة مساوياً لوقت تنفيذها ، فإن حلقة الأحداث ستشغلها إلى ما لا نهاية.
بعد ذلك ، يذهب إلى Render ويقوم بأداء المهام منه. يتم تحسين المهام من Render بواسطة المستعرض ، وإذا اعتبر أنه ليست هناك حاجة لإعادة رسم أي شيء في هذه الدورة ، فستذهب "حلقة الأحداث" ببساطة إلى أبعد من ذلك. بعد ذلك ، تأخذ حلقة الأحداث مرة أخرى المهام من المهام وتطلب منها مهمة
واحدة فقط ، المهمة الأولى في قائمة الانتظار ، وتمررها إلى CallStack وتذهب أبعد من ذلك في الحلقة.
إذا لم يكن لدى أحد العملاء مهام ، فحينئذٍ ينتقل Event Loop إلى التالي. وعلى العكس ، إذا كانت مهام العميل تستغرق الكثير من الوقت ، فسوف ينتظر العملاء الباقون دورهم. وإذا تحولت المهام من بعض العملاء إلى ما لا نهاية ، فستتجاوز Call Stack ، ويبدأ المستعرض في أقسم:
الشكل 3 الآن وقد فهمنا كيف تعمل Event Loop ، فقد حان الوقت لمعرفة ما يحدث بعد تنفيذ مقتطفات الشفرة في بداية هذه المقالة.
function foo() { setTimeout(foo, 0); } foo();
نرى أن الوظيفة foo تستدعي نفسها بشكل متكرر من خلال setTimeout بالداخل ، ولكن مع كل مكالمة ، تنشئ مهمة عميل Tasks. كما نذكر ، في حلقة "حلقة الأحداث" ، عند تنفيذ قائمة انتظار المهام من المهام ، يستغرق مهمة واحدة فقط في الحلقة. ثم هناك مهام من Microtasks و Render. لذلك ، لن يتسبب هذا الجزء من التعليمات البرمجية في معاناة "حدث الأحداث" وبدء مهامه إلى الأبد. لكنه سوف يطرح مهمة جديدة للعميل المهام على كل لفة.
دعونا نحاول تشغيل هذا البرنامج النصي في متصفح Google Chrome. للقيام بذلك ، قمت بإنشاء مستند HTML بسيط و script.js متصل به جزء التعليمات البرمجية هذا فيه. بعد فتح المستند ، انتقل إلى أدوات المطورين وافتح علامة تبويب Perfomance وانقر على زر "بدء ملفات التعريف وإعادة تحميل الصفحة":
الشكل 4نرى أن المهام من المهام يتم تنفيذها واحدة تلو الأخرى ، تقريبًا مرة واحدة كل 4 مللي ثانية.
النظر في اللغز الثاني:
function foo() { Promise.resolve().then(foo); } foo();
نرى هنا نفس الشيء كما في المثال أعلاه ، ولكن استدعاء foo يضيف مهامًا من Microtasks ، وكلها تتم حتى تنتهي. هذا يعني أنه إلى أن تنتهي حلقة الأحداث ، لن يتمكن من الانتقال إلى العميل التالي :( ونرى مرة أخرى
صورة حزينة.
ألقِ نظرة على ذلك في أدوات التطوير:
الشكل 5نرى أنه يتم تنفيذ المهام الدقيقة مرة واحدة كل 0.1 مللي ثانية تقريبًا ، وهذا أسرع 40 مرة من قائمة انتظار المهام. كل ذلك لأنهم يؤدونها دفعة واحدة. في مثالنا ، تنتقل قائمة الانتظار إلى ما لا نهاية. للتصور ، قمت بتخفيضه إلى 100000 تكرار.
هذا كل شئ!
آمل أن تكون هذه المقالة مفيدة لك ، والآن تفهم كيف تعمل Event Loop وما يحدث في أمثلة التعليمات البرمجية أعلاه.
وداعا :) ونراكم قريبا. إذا أعجبك ذلك ، فأعجبني واشترك في قناتي :)