مدل اجرای جاوا اسکریپت ظریف است و به راحتی قابل درک نیست. یادگیری در مورد حلقه رویداد در هسته آن می تواند کمک کند.
جاوا اسکریپت یک زبان تک رشته ای است که برای انجام وظایف یک به یک ساخته شده است. با این حال، حلقه رویداد به جاوا اسکریپت اجازه میدهد تا با شبیهسازی سیستمهای برنامهنویسی همزمان، رویدادها و فراخوانها را به صورت ناهمزمان مدیریت کند. این کارکرد برنامه های جاوا اسکریپت شما را تضمین می کند.
حلقه رویداد جاوا اسکریپت چیست؟
حلقه رویداد جاوا اسکریپت مکانیزمی است که در پس زمینه هر برنامه جاوا اسکریپت اجرا می شود. این به جاوا اسکریپت اجازه می دهد تا وظایف را به ترتیب بدون مسدود کردن رشته اصلی خود انجام دهد. این به عنوان برنامه نویسی ناهمزمان شناخته می شود.
حلقه رویداد یک صف از وظایف را برای اجرا نگه میدارد و آن وظایف را به API وب مناسب برای اجرا در یک زمان تغذیه میکند. جاوا اسکریپت این وظایف را پیگیری می کند و هر کدام را بر اساس سطح پیچیدگی کار انجام می دهد.
برای درک نیاز به حلقه رویداد جاوا اسکریپت و برنامه نویسی ناهمزمان. شما باید درک کنید که اساساً چه مشکلی را حل می کند.
برای مثال این کد را در نظر بگیرید:
function longRunningFunction() {
// This function does something that takes a long time to execute.
for (var i = 0; i < 100000; i++) {
console.log("Hello")
}
}
function shortRunningFunction(a) {
return a * 2 ;
}
function main() {
var startTime = Date.now();
longRunningFunction();
var endTime = Date.now();
// Prints the amount of time it took to execute functions
console.log(shortRunningFunction(2));
console.log("Time taken: " + (endTime - startTime) + " milliseconds");
}
main();
این کد ابتدا تابعی به نام longRunningFunction() تعریف می کند. این تابع نوعی کار پیچیده و زمان بر را انجام می دهد. در این مورد، یک حلقه for را بیش از 100000 بار تکرار می کند. این بدان معنی است که console.log (“Hello”) 100000 بار اجرا می شود.
بسته به سرعت کامپیوتر، این می تواند زمان زیادی طول بکشد و () shortRunningFunction را از اجرای فوری تا تکمیل عملکرد قبلی مسدود کند.
برای زمینه، در اینجا مقایسه ای از زمان صرف شده برای اجرای هر دو تابع است:
و سپس تک shortRunningFunction():
تفاوت بین عملیات 2351 میلیثانیهای و عملیات 0 میلیثانیه زمانی آشکار است که قصد دارید یک برنامه کاربردی بسازید.
چگونه حلقه رویداد به عملکرد برنامه کمک می کند
حلقه رویداد دارای مراحل و بخش های مختلفی است که به کارکرد سیستم کمک می کند.
پشته تماس
پشته فراخوانی جاوا اسکریپت برای اینکه جاوا اسکریپت چگونه تماس های عملکرد و رویداد را از برنامه شما مدیریت می کند ضروری است. کد جاوا اسکریپت از بالا به پایین کامپایل می شود. با این حال، Node.js، هنگام خواندن کد، Node.js فراخوانی های تابع را از پایین به بالا اختصاص می دهد. همانطور که خوانده می شود، توابع تعریف شده را به عنوان فریم یکی یکی به پشته تماس منتقل می کند.
پشته فراخوانی مسئول حفظ زمینه اجرا و ترتیب صحیح توابع است. این کار را با عملکرد به عنوان یک پشته Last-In-First-Out (LIFO) انجام می دهد.
این بدان معناست که آخرین فریم تابعی که برنامه شما به پشته تماس فشار میدهد، اولین فریمی است که از پشته خارج شده و اجرا میشود. این اطمینان حاصل می کند که جاوا اسکریپت ترتیب صحیح اجرای تابع را حفظ می کند.
جاوا اسکریپت هر فریم را از پشته خارج می کند تا زمانی که خالی شود، به این معنی که اجرای تمام توابع به پایان رسیده است.
Libuv Web API
هسته اصلی برنامه های ناهمزمان جاوا اسکریپت libuv است. کتابخانه libuv به زبان برنامه نویسی C نوشته شده است که می تواند با API های سطح پایین سیستم عامل تعامل داشته باشد. این کتابخانه چندین API را فراهم می کند که به کد جاوا اسکریپت اجازه می دهد تا به موازات سایر کدها اجرا شود. API برای ایجاد رشته ها، API برای برقراری ارتباط بین رشته ها و API برای مدیریت همگام سازی رشته ها.
به عنوان مثال، زمانی که از setTimeout در Node.js برای توقف موقت اجرا استفاده می کنید. تایمر از طریق libuv تنظیم میشود، که حلقه رویداد را مدیریت میکند تا پس از سپری شدن تاخیر مشخصشده، عملکرد برگشت به تماس را اجرا کند.
به طور مشابه، هنگامی که عملیات شبکه را به صورت ناهمزمان انجام می دهید، libuv آن عملیات را به صورت غیر مسدود کننده انجام می دهد، و اطمینان حاصل می کند که سایر وظایف می توانند بدون انتظار برای پایان عملیات ورودی/خروجی (I/O) به پردازش ادامه دهند.
پاسخ به تماس و صف رویداد
صف برگشت تماس و رویداد جایی است که توابع پاسخ به تماس منتظر اجرا هستند. هنگامی که یک عملیات ناهمزمان از libuv کامل می شود، تابع تماس مربوطه آن به این صف اضافه می شود.
دنباله به این صورت است:
- جاوا اسکریپت وظایف ناهمزمان را به libuv منتقل می کند تا بتواند آن را مدیریت کند و بلافاصله به کار بعدی ادامه می دهد.
- هنگامی که کار ناهمزمان به پایان می رسد، جاوا اسکریپت تابع تماس خود را به صف پاسخ به تماس اضافه می کند.
- جاوا اسکریپت به اجرای سایر وظایف در پشته تماس ادامه می دهد تا زمانی که همه چیز را به ترتیب فعلی انجام دهد.
- هنگامی که پشته تماس خالی شد، جاوا اسکریپت به صف برگشت تماس نگاه می کند.
- اگر تماسی در صف وجود داشته باشد، اولین تماس را به پشته تماس فشار داده و آن را اجرا می کند.
به این ترتیب، وظایف ناهمزمان رشته اصلی را مسدود نمیکند و صف برگشت تضمین میکند که تماسهای مربوطه آنها به ترتیبی که تکمیل شدهاند اجرا میشوند.
چرخه حلقه رویداد
حلقه رویداد همچنین دارای چیزی به نام صف microtask است. این صف ویژه در حلقه رویداد، ریزتسکهایی را نگه میدارد که به محض اتمام کار فعلی در پشته تماس، برنامهریزی شدهاند. این اجرا قبل از رندر بعدی یا تکرار حلقه رویداد اتفاق می افتد. Microtasks وظایفی با اولویت بالا هستند که بر وظایف معمولی در حلقه رویداد ارجحیت دارند.
معمولاً هنگام کار با Promises یک ریزکار ایجاد می شود. هر زمان که یک Promise حل یا رد شود، تماس های مربوط به آن .then() یا .catch() به صف microtask می پیوندد. میتوانید از این صف برای مدیریت کارهایی که پس از عملیات جاری نیاز به اجرای فوری دارند، مانند بهروزرسانی رابط کاربری برنامهتان یا مدیریت تغییرات حالت، استفاده کنید.
به عنوان مثال، یک برنامه وب که واکشی داده را انجام می دهد و UI را بر اساس داده های بازیابی شده به روز می کند. کاربران می توانند با کلیک مکرر روی یک دکمه، این واکشی داده را فعال کنند. هر کلیک یک دکمه عملیات بازیابی ناهمزمان داده را آغاز می کند.
بدون microtasks، حلقه رویداد برای این کار به صورت زیر کار می کند:
- کاربر بارها روی دکمه کلیک می کند.
- هر کلیک یک دکمه عملیات واکشی ناهمزمان داده را آغاز می کند.
- با تکمیل عملیات واکشی داده ها، جاوا اسکریپت تماس های مربوطه خود را به صف کار معمولی اضافه می کند.
- حلقه رویداد پردازش وظایف را در صف کار معمولی شروع می کند.
- بهروزرسانی رابط کاربری مبتنی بر نتایج واکشی دادهها به محض اینکه وظایف عادی اجازه میدهند اجرا میشود.
با این حال، با microtasks، حلقه رویداد متفاوت عمل می کند:
- کاربر بر روی دکمه مکرر کلیک می کند و عملیات واکشی ناهمزمان داده را راه اندازی می کند.
- با تکمیل عملیات واکشی دادهها، حلقه رویداد تماسهای مربوطه خود را به صف microtask اضافه میکند.
- حلقه رویداد بلافاصله پس از اتمام کار فعلی (کلیک روی دکمه) پردازش وظایف را در صف microtask شروع می کند.
- بهروزرسانی رابط کاربری مبتنی بر نتایج واکشی دادهها قبل از انجام کار معمولی بعدی اجرا میشود و تجربه کاربر پاسخگوتری را ارائه میدهد.
در اینجا یک مثال کد است:
const fetchData = () => {
return new Promise(resolve => {
setTimeout(() => resolve('Data from fetch'), 2000);
});
};
document.getElementById('fetch-button').addEventListener('click', () => {
fetchData().then(data => {
// This UI update will run before the next rendering cycle
updateUI(data);
});
});
در این مثال، هر کلیک بر روی دکمه “Fetch” fetchData() را فراخوانی می کند. هر عملیات واکشی داده به عنوان یک وظیفه کوچک برنامه ریزی می شود. بر اساس دادههای واکشی شده، بهروزرسانی رابط کاربری بلافاصله پس از تکمیل هر عملیات واکشی، قبل از هر کار رندر یا حلقه رویداد دیگری اجرا میشود.
این تضمین میکند که کاربران دادههای بهروزرسانیشده را بدون هیچ گونه تأخیر ناشی از سایر وظایف در حلقه رویداد مشاهده کنند.
استفاده از ریزکارها در سناریوهایی مانند این میتواند از جابجایی UI جلوگیری کند و تعاملات سریعتر و روانتری را در برنامه شما ایجاد کند.
مفاهیم حلقه رویداد برای توسعه وب
درک حلقه رویداد و نحوه استفاده از ویژگی های آن برای ساخت برنامه های کاربردی و پاسخگو ضروری است. حلقه رویداد قابلیتهای ناهمزمان و موازی را فراهم میکند، بنابراین میتوانید بدون به خطر انداختن تجربه کاربر، وظایف پیچیده را در برنامهتان به طور موثر انجام دهید.
Node.js همه چیز مورد نیاز شما را فراهم می کند، از جمله وب کارگران برای رسیدن به موازی سازی بیشتر در خارج از رشته اصلی جاوا اسکریپت.