بیاید با یک مثال شروع کنیم. به نظرتون خروجی کد زیر کدوم گزینه است؟
اگر با جاوا اسکریپت و event loop آشنا باشید میتونید که گزینه a نیست. جواب بین گزینه b و c هست.
اگر با micro task queue آشنا باشید میدونید چرا جواب c درسته و b غلط.
بریم تحلیلش کنیم:
اول از همه که عدد 1 پرینت میشه. عدد 2 در setTimeout هست و asynchronous اجرا میشه . بنابراین بلافاصله پرینت نمیشه و به task queue میره. بعدش عدد 3 پرینت میشه. promise ها هم asyncronous هستند. پس اجرای promise هم به task queue میره (!). بعد عدد 5 پرینت میشه.
به نظر میرسه که باید عدد 2 پرینت بشه و بعدش عدد 4. در حالیکه با اجرای این کد میبینیم که اول عدد 4 اجرا میشه و بعد عدد 2.
چرا ؟
جوابش به ساختار جاوااسکریپت در اجرای دستورات برمیگرده. Promise ها در صفی ذخیره میشوند بنام micro task queue. اعضای این صف بعد از اجرای همه callback های یک event، و قبل از اینکه جاوااسکریپت event loop را بررسی کند، اجرا میشوند. در واقع اعضای این صف با اولویت بالاتری اجرا میشوند.
در واقع بعد از اجرای console.log(5) ، اجرای اسکریپت فعلی تمام میشه و وقتشه جاوااسکریپت به صف task ها سر بزنه. ولی اول به micro task queue سر میزنه و میبینه یک Promise هست که باید صدا زده بشه.
بنابر این اول عدد ۴ اجرا میشه. event loop همچنان به micro queue task نگاه میکنه و تا زمانی که خالی نباشه سراغ task queue نمیره. با اجرای عدد ۴ و خالی شدن micro queue task ، حالا به سراغ task های عادی میره و console.log(2) رو اجرا میکنه.
بریم یک مثال دیگه ببینیم:
در این کد چه اتفاقی می افته؟ لطفا یک دور خودتون سعی کنین تحلیل کنین و بعد بیاین سراغ اتفاقی که واقعا می افته.قدم اول: نوبت به اجرای اسکریپت اصلی توسط event loop میرسه. اسکریپت اصلی به stack میره و اجراش شروع میشه.
قدم دوم: callback اول برای کلیک روی دکمه رجیستر میشه.
قدم سوم: callback دوم برای کلیک روی دکمه رجیستر میشه.
قدم چهارم: روی دکمه کلیک میشه و callback اول جهت اجرا شدن به stack میره.
دقت کنید که الان داخل stack هم اسکریپت اصلی رو داریم و هم callback اول رو داریم. تا وقتی button.click تموم نشه ، اسکریپت ما در حال اجراست.
قدم پنجم: دستور لاگ کردن Microtask1 میره در micro task queue میشینه
قدم ششم: دستور لاگ کردن Listener 1 اجرا میشه.
قدم هفتم و مهم ترین قسمت : اجرای callback اول تموم میشه و بر میگرده به اسکریپت اصلی.
قدم هشتم: callback دوم برای اجرا فراخوانی میشه و به stack میره.
قدم نهم: دستور لاگ کردن Microtask 2 میره در micro task queue میشینه.
قدم دهم: دستور لاگ کردن Listener 2 اجرا میشه.
قدم یازدهم: اجرای callback دوم هم تموم میشه و برمیگرده به اسکریپت اصلی.
قدم دوازدهم: اجرای button.click تموم میشه و به دنبالش اجرای اسکریپت اصلی تموم میشه.
قدم سیزدهم: قبل از اینکه سراغ task ها بره، میره سراغ micro task queue. داخل micro task queue یک task پیدا میکنه و دستور لاگ کردنMicrotask 1 رو اجرا میکنه.
قدم چهاردهم: هنوز micro task queue خالی نشده. پس task بعدیش رو اجرا میکنه و دستور لاگ کردن Microtask 2 رو اجرا کنه.
قدم پانزدهم: micro task queue خالی شده. پس میره سراغ task queue و باز هم چیزی نمی بینه و اجرای کد تموم میشه.
قدم شانزدهم: event loop همچنان منتظره تا رویداد جدیدی ثبت بشه.
خروجی :
Listener 1, Listener 2, Microtask 1, Microtask 2
مقاله های مرتبط:
تفاوت stopPropagation و stopImmediatePropagation
امیدوارم از این مقاله لذت ببرید و براتون مفید باشه.
اگر دوست دارید میتونید از طریق صفحه لینکدین با من در ارتباط باشید :)