تا به حال به این فکر کرده اید که چگونه برنامه های وب به طور پیوسته به ورودی های کاربر پاسخ می دهند و وظایف مختلف را به طور همزمان انجام می دهند؟ راز این عملکرد در حلقه رویداد (Event Loop) جاوا اسکریپت نهفته است.
به زبان ساده، حلقه رویداد یک چرخه بی پایان است که مفسر JavaScript به طور مداوم آن را اجرا می کند. این چرخه وظایف مختلف را در پاسخ به رویدادهایی مانند کلیک کاربر، حرکت موس، بارگیری اسکریپت و غیره مدیریت می کند.
چگونه عمل می کند؟
حلقه رویدادها(Event Loop) به صورت single thread عمل میکند، به این معنی که تنها میتواند یک وظیفه را در هر زمان اجرا کند. این حلقه عملیات های غیرهمزمان را به وسیله توابع callback، promise ها و توابع async مدیریت میکند.
زمانی که یک عمل غیرهمزمان(async) مانند دریافت داده از API یا انتظار انقضای یک تایمر اجرا میشود بلافاصله به APIهای مرورگر منتقل میشود و thread اصلی آزاد میشود تا ادامه اجرای کد را انجام دهد. وقتی کار غیرهمزمان به پایان میرسد، تابع callback مربوط به آن در صف رویداد قرار میگیرد.
حلقه رویدادها به طور مداوم صف رویداد را برای عملیات های معلق بررسی میکند در حالی که thread اصلی خالی است. وقتی thread اصلی اجرای کد را به پایان میرساند، عملیات بعدی از صف رویداد را انتخاب میکند و تابع callback مربوط به آن را اجرا میکند.
به طور خلاصه مراحل عملکرد حلقه رویدادها را می توان به صورت زیر شرح داد:
انتظار برای رویداد: در این مرحله، مفسر Javascript منتظر می ماند تا یک رویداد رخ دهد.
بررسی صف وظایف: پس از رخ دادن یک رویداد، مفسر Javascript صف وظایف را بررسی می کند.
اجرای وظایف: وظایف مربوط به رویداد رخ داده از صف وظایف خارج شده و اجرا می شوند.
تکرار: پس از اتمام وظایف، چرخه رویداد به مرحله اول باز می گردد و منتظر رویداد بعدی می ماند.
چرا وجود حلقه رویدادها مهم است؟
حلقه رویدادها در Javascript به دلیل عملکرد ناهمزمانی که فراهم میکند، بسیار حیاتی است. این حلقه به توسعهدهندگان امکان میدهد تا کدهایی را بنویسند که واکنشگرا و کارآمد باشند و به آنها این قابلیت را میدهد که عملیاتهای ناهمزمان را مدیریت و هماهنگ کنند. با استفاده از حلقه رویدادها، میتوان از قفلکردن thread اصلی جلوگیری کرده و کارایی و پاسخگویی برنامهها را بهبود بخشید. به علاوه، این حلقه به توسعهدهندگان امکان میدهد که با استفاده از توابع callback، promise ها و توابع async، کدی را بنویسند که به رویدادها و ورودیهای مختلف پاسخ دهد.
انواع صف (queue) در حلقه رویدادها
در حلقه رویداد انواع مختلفی از صفها (Queue) وجود دارند که وظیفه مدیریت اجرای کدها و وظایف مختلف را بر عهده دارند. این انواع عبارتند از:
صف میکروتسک (Microtask Queue): این صف وظیفه مدیریت اجرای کدهایی را بر عهده دارد که به عنوان میکروتسک (Microtask) شناخته میشوند. این کدها معمولاً پس از اجرای کدهای اصلی و قبل از اجرای کدهایی که در Task Queue قرار دارند اجرا میشوند. معمولاً میکروتسکها از طریق عملیاتی از جمله Promise callbacks و MutationObserver callbacks ایجاد میشوند. این کدها معمولاً کارهایی انجام میدهند که به صورت فوری و با اولویت بالا نیاز به انجام دارند، مانند پردازش نتایج یک Promise یا واکشی تغییرات DOM ایجاد شده توسط MutationObserver.
صف وظیفه (Task Queue): این صف وظیفه مدیریت اجرای کدها را بر عهده دارد که به عنوان تسک (Task) شناخته میشوند. این کدها معمولاً به عنوان پاسخ به وقایعی از جمله اتمام اجرای یک کد، رخدادهای تایمر و درخواستهای IO (ورودی و خروجی) ایجاد میشوند. به عبارت دیگر، Task Queue کدهایی را که باید پس از اتمام اجرای کدهای فعلی و پس از پردازش ویژگیهای بلوک کننده مانند setTimeout و setInterval اجرا شوند، نگهداری میکند. این کدها معمولاً مربوط به کارهای غیرفوری و مدت زمان بیشتری برای اجرا دارند، مانند درخواستهای شبکه و عملیات IO دیگر.
صف انیمیشن (Animation Frame Queue): این صف وظیفه مدیریت اجرای کدها برای انیمیشنها را بر عهده دارد. این صف به طور خاص برای اجرای کدهایی که باید در هر فریم انیمیشن اجرا شوند، استفاده میشود. زمانی که مرورگر آماده است تا یک فریم جدید انیمیشن را نمایش دهد، آن را به عنوان یک اصطلاح و زمان مشخص شده برای اجرای کدهای مربوط به آن ارائه میدهد. کدهایی که باید در این فریم انیمیشن اجرا شوند، در صف فریم انیمیشن قرار میگیرند و سپس به ترتیب اجرا میشوند. با استفاده از صف فریم انیمیشن، میتوان به طور دقیق و هماهنگ انیمیشنهای سایت را ایجاد کرد و کدها را در زمان مناسب برای نمایش هر فریم انیمیشن اجرا کرد. این امر بهبود کارایی و پیوستگی انیمیشنها را فراهم میکند و تجربه کاربر را بهبود میبخشد.