راهنمای حلقه رویداد Node.js

Node.js یک محیط زمان اجرا جاوا اسکریپت منبع باز است که به شما امکان می دهد جاوا اسکریپت را خارج از مرورگر اجرا کنید. اگرچه Node.js تک رشته ای است، اما دارای یک حلقه رویداد است که آن را چند رشته ای می کند.
حلقه رویداد Node.js یک مکانیسم مهم در Node.js است که باعث می شود برنامه های Node.js به صورت همزمان و ناهمزمان اجرا شوند. تسلط بر حلقه رویداد Node.js به توسعه دهنده Node.js کمک می کند تا درک کند که برنامه های Node.js چگونه زیر سرپوش اجرا می شوند.
در این مقاله اصول اولیه حلقه رویداد را یاد خواهید گرفت که با موضوعات و فرآیندها شروع می شود، سپس حلقه رویداد جاوا اسکریپت چگونه کار می کند و در نهایت، حلقه رویداد Node.js چگونه کار می کند.
Threads و Process چیست؟
برای تسلط بر حلقه رویداد Node.js، باید فرآیندها و رشته ها را درک کنید.
یک برنامه نویس می تواند برنامه هایی بنویسد که وظایف مختلفی را با زبان های برنامه نویسی مختلف انجام می دهند. در حالی که برخی از زبان های برنامه نویسی می توانند تنها یک کار را در یک زمان اجرا کنند، زبان های برنامه نویسی دیگر می توانند چندین کار را به طور همزمان اجرا کنند.
یک فرآیند شامل چندین کار است که در یک برنامه از ابتدا تا انتها اجرا می شوند، در حالی که یک رشته، اجرای یک کار فردی است.
یک فرآیند شامل تمام مراحلی است که یک برنامه برای اجرا تا اتمام طی می کند. این یک برنامه در حال اجرا است. یک برنامه ممکن است یک یا چند فرآیند مستقل داشته باشد که هر کدام فضای حافظه یا آدرس مخصوص به خود را دارند. یک فرآیند ممکن است یک یا چند رشته در خود داشته باشد.
thread یک واحد اجرا است که بخشی از یک فرآیند است، مانند یک وظیفه در یک برنامه. یک رشته دارای شناسه رشته، یک مجموعه ثبت و یک پشته است. یک رشته همچنین بخش کد، بخش داده، منابع سیستم عامل و فضای حافظه خود را با رشته های دیگر در یک فرآیند به اشتراک می گذارد.
کد زیر حاوی یک تابع isNumberEven
است که زوج بودن یک عدد را تحلیل می کند و یک تابع isNumberOdd
که فرد بودن یک عدد را تحلیل می کند. یک فرآیند شامل اجرای این کد از ابتدا تا انتها است، در حالی که یک رشته شامل اجرای عملکردهای فردی است.
function isNumberEven(number) { if (number % 2 === 0) { return true; } else { return false; } } function isNumberOdd(number) { if (number % 2 !== 0) { return true; } else { return false; } } isNumberEven(6); isNumberOdd(1);
Single-thread و Multi-thread چیست؟
همه زبان های برنامه نویسی دارای یک موتور زمان اجرا هستند که کد آنها را اجرا می کند. برخی از موتورهای زمان اجرا تک رشته ای هستند (به این معنی که آنها فقط می توانند یک رشته را در یک زمان اجرا کنند)، در حالی که برخی از آنها چند رشته ای هستند (به این معنی که می توانند بیش از یک رشته را در یک زمان اجرا کنند).
نمودار زیر یک فرآیند تک رشته ای و یک فرآیند چند رشته ای را نشان می دهد:

یک زبان برنامه نویسی تک رشته ای دارای یک موتور زمان اجرا تک رشته ای است که وظایف یک برنامه را به صورت متوالی اجرا می کند. یک زبان برنامه نویسی چند رشته ای دارای یک موتور زمان اجرا چند رشته ای است که وظایف را در یک برنامه به طور همزمان اجرا می کند. یک موتور زمان اجرا چند رشته ای عملکرد بیشتری نسبت به موتور زمان اجرا تک رشته ای دارد.
زبان های برنامه نویسی مانند جاوا، سی شارپ و غیره چند رشته ای هستند، در حالی که زبان هایی مانند جاوا اسکریپت، پایتون و غیره تک رشته ای هستند.
زبان های برنامه نویسی تک رشته ای همزمان هستند، به این معنی که آنها وظیفه را در برنامه های خود به صورت متوالی اجرا می کنند. جاوا اسکریپت همزمان است، اما حلقه رویداد آن آن را ناهمزمان می کند.
در بخشهای آینده، نحوه عملکرد حلقه رویداد جاوا اسکریپت را خواهید آموخت و سپس بر حلقه رویداد Node.js مسلط خواهید شد.
حلقه رویداد جاوا اسکریپت چگونه کار می کند
شما باید بدانید که موتور زمان اجرا جاوا اسکریپت چگونه کد جاوا اسکریپت را اجرا می کند تا بتوانید حلقه رویداد جاوا اسکریپت را درک کنید.
موتور زمان اجرا جاوا اسکریپت عمدتاً شامل موارد زیر است:
پشته حافظه و
پشته تماس
پشته حافظه جایی است که متغیرهای اعلام شده در برنامه به فضای حافظه اختصاص داده می شود و پشته تماس جایی است که موتور زمان اجرا توابع را در برنامه برای اجرا ذخیره می کند.
موتور زمان اجرا جاوا اسکریپت کد زیر را به صورت همزمان و در این فرآیند گام به گام اجرا می کند:
فضای حافظه را برای تمام متغیرهای کد اختصاص می دهد.
پس از فشار دادن به پشته تماس، exponentiation
اجرا می کند.
تابع validatePassword
را پس از فشار دادن آن بر روی پشته تماس اجرا می کند.
function exponentiation(base, exponent) { let result = 1; for (let i = 0; i < exponent; i++) { result *= base; } return result; } function validatePassword(password) { const hasUppercase = /[AZ]/.test(password); const hasLowercase = /[az]/.test(password); const hasNumber = /[0-9]/.test(password); const isValidLength = password.length >= 8; if (hasUppercase && hasLowercase && hasNumber && isValidLength) { return "password is valid"; } else { return "password is invalid"; } } exponentiation(5, 3); validatePassword("Ab01234");
اگر کد شما حاوی یک تابع مسدود کننده است، که تابعی است که اجرای آن زمان زیادی می برد، این تابع تا زمانی که کامل شود، اجرای سایر توابع را مسدود می کند. کاربران نمی توانند با وب سایتی که دارای عملکرد مسدود کننده به عنوان بخشی از کد آن است، در حین اجرای عملکرد، تعامل داشته باشند.
کد زیر حاوی تابع fibonacci
است که اجرای آن به زمان نیاز دارد. موتور زمان اجرا ابتدا تابع factorial
و سپس تابع fibonacci
را شروع می کند که در طی آن تابع findMin
نمی تواند اجرا شود.
function factorial(n) { if (n === 0 || n === 1) { return 1; } let result = 1; for (let i = 2; i <= n; i++) { result *= i; } return result; } function fibonacci(num) { if (num <= 1) { return num; } return fibonacci(num - 1) + fibonacci(num - 2); } function findMin(numbers) { if (!numbers || numbers.length === 0) { throw new Error("Empty array provided"); } let min = numbers[0]; for (let i = 1; i < numbers.length; i++) { if (numbers[i] < min) { min = numbers[i]; } } return min; } let numbers = [4, 2, 8, 1, 6]; factorial(5); fibonacci(45); findMin(numbers);
برای اینکه برنامه در مثال بالا به صورت ناهمزمان اجرا شود، باید تابع fibonacci
با APIهای وب جاوا اسکریپت غیر مسدود کنید.
API های وب جاوا اسکریپت روی رشته اصلی اجرا نمی شوند، بلکه رشته های خود را ایجاد می کنند، که به آنها امکان می دهد همزمان اجرا شوند و اجرای سایر توابع در کد شما را مسدود نکنند.
میتوانید از این APIهای وب جاوا اسکریپت برای غیر مسدود کردن عملکردهای خود استفاده کنید:
AJAX و
پس ، اگر یک setTimeout
به کد خود اضافه کنید مانند این:
function factorial(n) { if (n === 0 || n === 1) { return 1; } let result = 1; for (let i = 2; i <= n; i++) { result *= i; } return result; } function fibonacci(num) { if (num <= 1) { return num; } return fibonacci(num - 1) + fibonacci(num - 2); } function findMin(numbers) { if (!numbers || numbers.length === 0) { throw new Error("Empty array provided"); } let min = numbers[0]; for (let i = 1; i < numbers.length; i++) { if (numbers[i] < min) { min = numbers[i]; } } return min; } let numbers = [4, 2, 8, 1, 6]; factorial(5); setTimeout(fibonacci(45), 3000); findMin(numbers);
توابع factorial
و findMin
روی thread اصلی اجرا می شوند، در حالی که تابع fibonacci
به طور همزمان روی یک رشته جداگانه اجرا می شود.
برای درک درست نحوه اجرای برنامه بالا، باید نحوه عملکرد حلقه رویداد جاوا اسکریپت را بدانید. حلقه رویداد جاوا اسکریپت مکانیزمی است که توسط آن وظایف در یک برنامه جاوا اسکریپت به صورت ناهمزمان اجرا می شود.
حلقه رویداد جاوا اسکریپت دارای یک صف برگشت است که توابعی را ذخیره می کند که اجرای آنها زمان می برد.
حلقه رویداد توابعی را که بلافاصله اجرا میشوند برای اجرا به صف برگشت ارسال میکند و توابع مسدودکننده را برای اجرا به رشتههای API وب میفرستد.
سپس، حلقه رویداد پس از سپری شدن زمان تنظیم شده، تابع مسدود کردن را به صف برگشت به تماس می فرستد. سپس حلقه رویداد قبل از فشار دادن تابع در صف برگشت به پشته تماس برای اجرا، خالی بودن پشته تماس را تحلیل می کند.
نمودار زیر نحوه عملکرد حلقه رویداد در جاوا اسکریپت را توضیح می دهد:

کد بالا که حاوی توابع factorial
، fibonacci
و findMin
، پس از گفت ن تابع setTimeout
به این صورت اجرا می شود.
حلقه رویداد تابع factorial
را برای اجرا به پشته فراخوانی فشار می دهد. سپس، حلقه رویداد تابع fibonacci
را به پشته فراخوانی فشار می دهد، اما تابع fibonacci
دارای یک تابع setTimeout
است که از اجرای فوری آن جلوگیری می کند. پس ، حلقه رویداد تابع fibonacci
را به یک رشته مجزا برای اجرای همزمان APIهای وب هدایت می کند.
سپس، حلقه رویداد تابع findMin
را برای اجرا به پشته فراخوانی فشار می دهد. هنگامی که زمان تنظیم شده در setTimeout
سپری می شود، حلقه رویداد تابع fibonacci
را برای اجرا به پشته فراخوانی فشار می دهد.
حلقه رویداد Node.js چگونه کار می کند
Node.js یک محیط زمان اجرا جاوا اسکریپت است که جاوا اسکریپت را قادر می سازد تا خارج از مرورگر اجرا شود، مانند رابط خط فرمان، سرورها و سخت افزار.
Node.js دارای یک حلقه رویداد است که شبیه به حلقه رویداد جاوا اسکریپت است. حلقه رویداد Node.js و حلقه رویداد جاوا اسکریپت دارای یک پشته تماس و یک صف برگشت تماس هستند. حلقه رویداد Node.js توسط کتابخانه ای به نام libuv که با زبان C نوشته شده است پیاده سازی و مدیریت می شود.
حلقه رویداد Node.js دارای شش مرحله است که عبارتند از:
فاز تایمر
فاز تماس های معلق
فاز بیکار
مرحله نظرسنجی
بستن فاز پاسخ به تماس
نمودار زیر نحوه عملکرد حلقه رویداد Node.js را نشان می دهد:

یک صف microtask وجود دارد که خارج از حلقه رویداد Node.js وجود دارد. صف microtask از nextTick queue
و Promise queue
تشکیل شده است. nextTick queue
تابع process.nextTick
را اجرا می کند، در حالی که Promise queue
.then
، .catch
و وعده های دیگر را اجرا می کند.
در بخش های آینده، با هر مرحله از حلقه رویداد Node.js آشنا خواهید شد.
فاز تایمر
سه تایمر در Node.js وجود دارد: setTimeout
، setInterval
و setImmediate
. setTimeout
و setInterval
در فاز تایمر اجرا می شوند. نمونه کد زیر در مرحله تایمر اجرا می شود:
setTimeout(() => { console.log("setTimeout callback executed"); }, 1000); setInterval(() => { console.log("setInterval callback executed"); }, 2000);
فاز تماس های معلق
عملیات I/O در مرحله نظرسنجی حلقه رویداد اجرا می شود. در طول مرحله نظرسنجی، برخی از عملیات ورودی/خروجی خاص بازخوانی به مرحله معلق تکرار بعدی حلقه رویداد موکول می شود. عملیات ورودی/خروجی که از تکرار قبلی در فاز تماسهای معلق اجرا میشد، به تعویق افتاد.
نمونه کد زیر در مرحله "بازخوانی های معلق" اجرا می شود:
const fs = require("fs"); fs.readFile(__filename, (err, data) => { if (err) throw err; console.log("File data:", data); });
فاز بیکار
فاز بیکار یک فاز عادی از حلقه رویداد Node.js نیست. این دوره ای است که در آن حلقه رویداد کاری جز انجام کارهای پس زمینه مانند تحلیل نتایج با اولویت پایین یا اجرای جمع آوری زباله ندارد.
برای رد شدن از مرحله بیکار و انجام ندادن کارهای پس زمینه، می توانید متد idle.ignore()
از بسته idle-gc در کد خود فراخوانی کنید.
const { idle } = require("idle-gc"); idle.ignore();
متد idle.ignore()
تضمین می کند که کد تا زمان تکمیل بدون هیچ دوره بیکاری به اجرا ادامه می دهد. با این حال، به دلیل مشکلات عملکردی که ایجاد میکند، باید از متد idle.ignore()
کم استفاده کرد.
مرحله نظرسنجی
مرحله نظرسنجی جایی است که عملیات I/O اجرا می شود. عملیات ورودی/خروجی داده ها را به یا از یک کامپیوتر منتقل می کند. حلقه رویداد عملیات ورودی/خروجی جدید را تحلیل می کند و آنها را در صف نظرسنجی اجرا می کند.
نمونه کد زیر در مرحله نظرسنجی اجرا می شود:
const http = require("http"); http.get("http://jsonplaceholder.typicode.com/posts/1", (res) => { console.log("HTTP request response received"); res.on("data", (chunk) => { // Do something with the data }); });
فاز را تحلیل کنید
مرحله تحلیل جایی است که تایمر setImmediate
اجرا می شود. حلقه رویداد Node.js زمانی که یک setImmediate
در برنامه وجود دارد به مرحله تحلیل می رود و مرحله نظرسنجی بیکار می شود یا زمانی که مرحله نظرسنجی کامل می شود.
نمونه کد زیر در مرحله تحلیل اجرا می شود:
setImmediate(() => { console.log("setImmediate callback executed"); });
بستن فاز پاسخ به تماس
مرحله تماس های بسته آخرین مرحله حلقه رویداد Node.js است. مرحله پاسخ به تماس بسته، جایی است که تماس های مربوط به رویداد بسته شدن یک سوکت و بسته شدن یک سرور HTTP
اجرا می شود.
نمونه کد زیر در مرحله تحلیل اجرا می شود:
const http = require("http"); const server = http.createServer((req, res) => { res.writeHead(200, { 'Content-Type': 'text/plain' }); res.end('Hello World\n'); }); server.listen(3000, () => { console.log('Server listening on port 3000'); server.close(() => { console.log('Server closed'); }); });
نتیجه
حلقه رویداد Node.js مکانیزمی است که برنامه نویسی ناهمزمان را در Node.js فعال می کند.
بهعنوان یک توسعهدهنده Node.js، اگر بر حلقه رویداد Node.js مسلط باشید، میتوانید درک کنید که کد Node.js شما چگونه زیر سرپوش اجرا میشود.
این مقاله فرآیندها و رشتهها، حلقه رویداد جاوا اسکریپت و حلقه رویداد Node.js را توضیح میدهد.
ارسال نظر