Event Loop جاوا اسکریپت اولین فرا خوانی را در صف callback می گیرد و به محض خالی شدن آن را به Call Stack اضافه می کند.
کد جاوا اسکریپت به صورت اجرا تا تکمیل اجرا میشود، به این معنی که اگر Call Stack در حال اجرای برخی از کدها باشد، Event Loop مسدود میشود و تا زمانی که استک دوباره خالی نشود، هیچ فرا خوانی از صف اضافه نخواهد شد.
به همین دلیل مهم است که Call Stack را با اجرای وظایف محاسباتی مسدود نکنید.
اگر کد زیادی را اجرا کنید یا صف callback خود را مسدود کنید، وب سایت شما پاسخگو نخواهد بود زیرا نمی تواند کد جاوا اسکریپت جدیدی را اجرا کند.
کنترلکنندههای رویداد، مانند onscroll
، وقتی فعال میشوند، وظایف بیشتری را به صف callback اضافه میکنند. به همین دلیل است که شما باید این callback ها را حذف کنید، به این معنی که آنها فقط در هر x
ms اجرا می شوند.
خودتان ببینید
کد زیر را به کنسول مرورگر خود اضافه کنید. همانطور که پیمایش می کنید، می توانید مشاهده کنید که چند وقت یکبار اسکرول کردن callback چاپ scroll
صورت می گیرد.
= () => console.log('scroll');
اگر بخواهیم برخی کارها را بدون مسدود کردن thread اصلی برای مدت طولانی اجرا کنیم، میتوانیم از رفتاری که در بالا توضیح داده شد به نفع خود استفاده کنیم.
قرار دادن کد ناهمزمان خود در یک callback و تنظیم setTimeout
روی 0ms به مرورگر این امکان را میدهد که کارهایی مانند بهروزرسانی DOM را قبل از ادامه اجرای کال بک انجام دهد.
در نمای کلی که در ابتدا نشان دادم، یک ویژگی اضافی را که دانستن آن مهم است کنار گذاشتم.
علاوه بر صف کال بک، صف دیگری وجود دارد که به طور انحصاری پرومیس ها را میپذیرد، صف جاب (job queue) است.
EcmaScript 2015 (یا ES6) اولین بار پرومیس ها را معرفی کرد، حتی اگر قبلاً در Babel در دسترس بوده است. اگر هنوز تفاوت بین اکما اسکریپت را با جاوااسکریپت را درک نکرده اید این مقاله می تواند در درک آن به شما کمک کند.
Promise ها روش دیگری برای مدیریت کدهای ناهمزمان به غیر از استفاده از callbacks است. آنها به شما این امکان را می دهند که به راحتی توابع ناهمزمان را بدون اینکه به چیزی که به آن جهنم کال بک ها یا هرم عذاب گفته می شود ختم شوید.
setTimeout(() => { console.log('Print this and wait'); setTimeout(() => { console.log('Do something else and wait'); setTimeout(() => { // ... }, 100); }, 100); }, 100)
با پرومیسها، این کد میتواند بسیار خواناتر شود:
// A promise wrapper for setTimeout const timeout = (time) => new Promise(resolve => setTimeout(resolve, time)); timeout(1000) .then(() => { console.log('Hi after 1 second'); return timeout(1000); }) .then(() => { console.log('Hi after 2 seconds'); });
این کد با دستور async/wait
خواناتر به نظر می رسد:
const logDelayedMessages = async () => { await timeout(1000); console.log('Hi after 1 second'); await timeout(1000); console.log('Hi after 2 seconds'); }; logDelayedMessages();
این خلاصهای سریع از نحوه عملکرد پرومیسها بود، اما در این مقاله، عمیقتر به این موضوع نمیپردازم. در صورتی که می خواهید در مورد آنها بیشتر بدانید، مقاله پرومیس ها در جاوااسکریپت را بررسی کنید.
چرا من اینجا از پرومیس ها صحبت می کنم؟ با در نظر گرفتن تصویر بزرگتر، پرومیسها کمی متفاوت از کال بک ها رفتار میکنند، زیرا آنها صف خاص خود را دارند.
صف جاب که به صف پرومیس نیز معروف است، مانند صف های سریع در یک شهربازی، نسبت به صف کال بک ها اولویت دارد. Event Loop قبل از پردازش صف کال بک ها را از صف پرومیس می گیرد.
بیایید به یک مثال نگاه کنیم:
console.log('a'); setTimeout(() => console.log('b'), 0); new Promise((resolve, reject) => { resolve(); }) .then(() => { console.log('c'); }); console.log('d');
با در نظر گرفتن دانش شما در مورد نحوه عملکرد صف های کال بک، ممکن است فکر کنید که خروجی a d b c خواهد بود.
اما از آنجایی که صف پرومیس نسبت به صف کال بک ها اولویت دارد، c قبل از b چاپ می شود، حتی اگر هر دو ناهمزمان باشند:
a d c b
امیدوارم اکنون متوجه شده باشید که در پشت صحنه کد جاوا اسکریپت چه اتفاقی می افتد. با پرومیس ها و event loop ها و کال استک ها آشنا شدیم و نسبت به جاوا اسکریپت به درک عمیق تری دست یافتیم. همچنین برای آشنایی با نحوه دیباگ کردن در جاوااسکریپت این مقاله را بررسی کنید.