Node.jsنودجیاس) چیست؟
در حقیقت، Node.js در نتیجهٔ تلاشهای دولوپرهای زبان جاوااسکریپت برای توسعۀ محیطی به وجود آمد که دولوپرها بتوانند کدهای جاوااسکریپت خود را علاوه بر داخل مرورگر، در سمت سرور نیز در قالب یک اپلیکیشن مستقل اجرا کنند.
در واقع، با وجود چنین قابلیتی دولوپرها میتوانند علاوه بر طراحی وبسایتهای تعاملی با زبان #جاوااسکریپت، برای توسعهٔ سایر اپلیکیشنها نیز از این زبان استفاده کنند به طوری که پس از ظهور نودجیاس، کاربردهای این زبان به اندازهٔ سایر زبانهای اسکریپتی همچون پایتون افزایش یافته است.
همچنین هر دو محیط اجرای جاوااسکریپت (هم مرورگر و هم محیط سمت سرور) روی موتور جاوااسکریپت تحت عنوان V8 اجرا میشوند. در حقیقت، این موتور کدهای جاوااسکریپت را گرفته و آنها را به یک اسکریپتی قابلفهم برای ماشین تبدیل میکند (کد قابلفهم برای ماشین یک کد اصطلاحاً Low Level یا سطح پایین است که کامپیوتر میتواند بدون تفسیر، خیلی سریع آن را اجرا کند.)
Node.js چیست؟
بر اساس تعریف ارائهشده در وبسایت رسمی Node.js:
نودجیاس یک محیط اجرای جاوااسکریپتی است که روی موتور اجرای کد جاوااسکریپتِ مرورگر کروم تحت عنوان V8 ساخته شده است.
V8 یک موتور اپنسورس برای اجرای کدهای جاوااسکریپت است که با زبان ++C نوشته شده است و همانطور که پیش از این نیز ذکر شد، این موتور کدهای جاوااسکریپتی را میگیرد و به یک کد قابلفهم برای ماشین تبدیل میکند. در واقع، V8 همچون توربینی با بهکارگیری زبان ++C موجب افزایش کارایی در خروجی کد جاوااسکریپت میشود.
همچنین V8 استانداردی تحت عنوان ECMAScript را پیادهسازی میکند که توسط سازمان بینالمللی Ecma و به منظور استانداردسازی زبان جاوااسکریپت ساخته شد. این موتور توانایی اجرایی کدها به صورت مستقل را دارا است و میتواند در سایر اپلیکیشنهای نوشته شده با ++C نیز اِمبدد شود. به عبارت دیگر، دولوپرها میتوانند کد خود را به زبان ++C بنویسند و این در حالی است که امکان اجرای آن در محیط اجرای کدهای جاوااسکریپت و همچنین نوشتن کد به زبان جاوااسکریپت نیز برای ایشان فراهم است که این مسئله موجب میشود تا دولوپرها با اِمبدد کردن موتور V8 در کد نوشته شده با زبان سیپلاسپلاس خود، فیچرهایی را به زبان جاوااسکریپت بیفزایند تا این کد قابلیتهای بیشتری نسبت به سایر استانداردهای مشخصشده در ECMAScript را داشته باشد.
به غیر از تعریف فوق، تعاریف و تفاسیر دیگری نیز برای نودجیاس ارائه شدهاند که در ادامه به معرفی تعریف جامعتری از این محیط میپردازیم:
نودجیاس از مُدلی پیروی میکند که مبتنی بر رویداد (Event-driven) بوده و همچنین این مدل فرآیندهای ورودی و خروجی (I/O) را اصلاً بلاک نمیکند به طوری که استفاده از چنین مدلی موجب سَبکی و کارآمدی محیط اجرای نودجیاس شده است.
تعریف اول از نودجیاس را در ابتدای مقاله مورد بحث قرار دادیم؛ حال به بررسی تعریف دوم خواهیم پرداخت تا دریابیم که چرا نودجیاس محبوب شده است.
درآمدی بر Blocking I/O و Non-blocking I/O
I/O به درخواستهای ورودی و خروجی از یک سیستم اشاره دارد و فرآیندهای گوناگونی را شامل میشود که از آن جمله میتوان به فرآیندهای به اصطلاح Read یا Write (به ترتیب به معنی خواندن و نوشتن) روی یکسری فایل سیستمی یا ارسال یک ریکوئست (درخواست) از نوع HTTP به یک API را نام برد. معمولاً چنین ریکوئستهایی زمانبَر هستند، لذا سیستم در هنگام دریافت درخواستهایی از جنس I/O، فانکشنهای دیگر را بلاک (مسدود) میکند تا بتواند در کمترین زمان ممکن پاسخ مناسب را به این درخواستها بدهد. برای درک بهتر این موضوع، سناریوی فرضی زیر را در نظر بگیرید:
یک درخواست از طرف سیستم به دیتابیس ارسال شده است تا اطلاعات کاربر شماره یک و همچنین کاربر شماره دو را دریافت کرده و آنها را در یک صفحه یا در کنسول چاپ کند. پاسخ به این ریکوئست کمی زمانبَر است اما هر دو درخواست برای چاپ دیتای کاربران میتوانند به صورت مستقل از هم و همزمان انجام شوند.
حال فرض کنید که ارسال ریکوئست و دریافت ریسپانس (پاسخ) از دیتابیس بر طبق فرآیند Blocking I/O (مسدود کردن ورودی/خروجی) انجام میشد؛ در این روش پاسخ به ریکوئستی که برای دریافت دیتای کاربر دوم ارسال شده داده نمیشود مگر زمانی که کار ریکوئست اول (دریافت دیتای کاربر قبلی) به اتمام رسیده باشد که این اصلاً خوب نیست!
اگر چنین ریکوئستی به یک وبسرور ارسال شود، بایستی به ازای هر ریکوئست برای دریافت دیتای مربوط به هر کاربر، یک به اصطلاح Thread جدید ایجاد شود اما زبان جاوااسکریپت یک زبان به اصطلاح Single-threaded (تَک تِرِدی) است؛ بنابراین برای تَسکهایی که درخواست به یک وب سرور ارسال میشود و نیاز به اجرا به صورت به اصطلاح Multi-threaded (چند تِرِدی) دارند، زیاد مناسب نخواهد بود (لازم به ذکر است که زبان جاوااسکریپت کاملاً تکتِردی نبوده اما دارای یک Event Loop است که به صورت تَک تِرِدی اجرا میشود که در ادامۀ مقاله، این مورد را بیشتر توضیح میدهیم.)
با در نظر گرفتن این شرایط، سؤالی که پیش میآید این است که در زبان جاوااسکریپت درخواستهای همزمان چگونه اجرا میشوند؟ در پاسخ به این سؤال فرآیندی را معرفی خواهیم کرد که به روش Non-blocking I/O (مسدود نکردن درخواستهای ورودی/خروجی) اجرا شده و برای انجام درخواستهای همزمان بسیار کارآمد است.
برای مثال، با بهکارگیری فرآیندهایی که در آن یکی از چند درخواست همزمان بلاک نمیشوند، سیستم میتواند یک ریکوئست را برای دریافت دیتای مربوط به کاربر شماره دو آغاز کند، بدون اینکه منتظر دریافت پاسخ مربوط به دیتای کاربر شماره یک بماند. در واقع، سیستم هر دو درخواست را به صورت موازی اجرا میکند و در کوتاهترین زمان ممکن پاسخ را به کاربران ارسال میکند که در این صورت دیگر نیازی به اجرای تَسکها به صورت چند تِردی نیست چرا که سرور میتواند چندین درخواست را به صورت همزمان هَندل کند.
درآمدی بر Event Loop در جاوااسکریپت
هر آنچه در اپلیکیشن اتفاق میافتد و دولوپر میتواند به آن پاسخ دهد را اصطلاحاً Event میگویند. به طور کلی دو نوع ایونت (رویداد) در پلتفرم نودجیاس وجود دارد که عبارتند از:
– ایونتهای سیستمی: اینگونه ایونتها در هستهٔ ++C و در نتیجۀ فراخوانی یک لایبرری تحت عنوان libuv اتفاق میافتد (به عنوان مثال، میتوان به پایان رسیدن فرآیند Read یک فایل را مثال زد.)
– ایونتهای سفارشی شده: این دست رویدادها در هستۀ جاوااسکریپت اتفاق میافتند.
حال پس از آشنایی با مفهوم Event (رویداد)، در ادامه قصد داریم به تشریح گامبهگام نحوۀ اجرای Event Loop (حلقهای از رویدادها) در جاوااسکریپت بپردازیم.
همانطور که در تصویر فوق مشخص است، ابتدا تابعی تحت عنوان ()main وارد Call Stack (پشتهای به منظور فراخوانی و اجرای توابع) میشود و در ادامه دستور ()console.log وارد Call Stack شده و فوراً اجرا میشود و از پشته نیز خارج میشود. در این مرحله، تابع (setTimeout(2000 وارد پشته میشود (تابع (setTimeout(2000 یک ایپیآی برای نودجیاس است و وقتی آن را فراخوانی میکنیم یک جفت Event-Callback را رجیستر میکنیم که در آن ایونتی به مدت ۲۰۰۰ میلیثانیه منتظر مانده و سپس مجدداً تابع Callback فراخوانی میشود.) پس از رجیستر کردن جفت Event-Callback، تابع (setTimeout(2000 از اِستک (پُشته) خارج میشود.
در مرحلهٔ بعد، تابع (setTimeout(0 به همین شیوه رجیستر میشود؛ حال دو ایپیآی Node داریم که منتظر اجرا هستند. تابع (setTimeout(0 بدون منتظر ماندن به Callback Queue (صف فراخوانی مجدد تابع) منتقل میشود و پس از ۲۰۰۰ ثانیه نیز تابع (setTimeout(2000 به صف Callback منتقل میشود. در صف Callback، این تابع صبر میکند تا پشته فراخوانی تابع خالی شود، زیرا تنها یک دستور میتواند در یک زمان اجرا شود و این در حالی است که فراخوانی توابع برای اجرا توسط Event Loop هندل میشود و در نهایت هم دستور ()console.log اجرا میشود و تابع ()main از پشته فراخوانی توابع خارج میشود.
در آنچه توضیح دادیم، Event Loop، که وظیفۀ هندل کردن توابع را بر عهده داشت، میبیند که پشته توابع خالی شده است اما صف Callback خالی نیست؛ بنابراین این حلقه توابعی را که برای اجرای مجدد فراخوانی شدهاند، بر اساس قانون FIFO از این پشته خارج کرده و وارد Call Stack میکند تا به ترتیب اجرا شوند (FIFO مخفف واژگان First In, First Out است و در ساختمان داده بدان معنا است که آنچه در ابتدا وارد پشته شود، ابتدا نیز خارج یا اجرا میگردد.)
درآمدی بر پَکیج مَنجر NPM
NPM که مخفف واژگان Node Package Manager است، پَکیج مَنجر نودجیاس حاوی مجموعهای از لایبرریهایی است که با مشارکت کامیونیتی بزرگی از دولوپرهای جاوااسکریپت توسعه یافته است و پاسخی به نیازهای بسیاری از مسائل دولوپرها است.
آشنایی با ماژولهای پلتفرم Node.js
یک ماژول در نُود بلوکی از کد با قابلیت استفادهٔ مجدد است و اجرای این بلوک از کد بر روی کدهای دیگر تأثیر نمیگذارد. همچنین دولوپرها میتواند ماژولهای خود را نوشته و از آنها در برنامههای مختلف استفاده کنند و این در حالی است که خودِ پلتفرم نودجیاس نیز متشکل از مجموعۀ ماژولهای مختلفی است که دولوپرها میتوانند بدون نصب، آنها را مورد استفاده قرار دهند.