دسته: Node.js

Node.js: قدرقدرت وارد می‌شود!

Node.js: قدرقدرت وارد می‌شود!

در گذشته نه چندان دور، استفاده از JavaScript (یا به فارسی: جاوااسکریپت) به‌عنوان زبان برنامه نویسی سمت‌سرور (Server-side) رویایی دست نیافتنی بود. مثلاً شما نمی‌توانستید پایتون یا پرل را کنار بگذارید و از جاوااسکریپت به عنوان جایگزین استفاده کنید! دلایل مختلفی هم داشت. غنی‌نبودن Syntax، امکانات کم، محدودیت بسیار بالای API، عدم اشتراک API میان موتورهای مختلف اجرا کننده ولی از همه مهم‌تر کدام مشکل بود؟ مشکل سرعت موتورهای JavaScript. (البته منکر وجود Netscape Enterprise Server و MarkLogic نمی‌شوم ولی استفاده سمت‌سرور نسبت به‌گونه امروزی بسیار بسیار محدودتر بود، مخصوصاً که باید برای آن هزینه پرداخت می‌شد)

ECMAScript

البته این نکته هم حائز اهمیت است که اشاره به آنچه در حال حاضر JavaScript می‌نامیم تحت عنوان گونه‌ای از ECMAScript صحیحتر است، چرا که تغییرات بسیار زیادی کرده ولی امروز پا به پای ECMAScript پیش می‌رود.
ECMAScript در اصل یک استاندارد بین‌المللی براساس JavaScript 1.1 است. (جاوااسکریپت یک دیالکت از ECMAScript است)

اگر به انواع نحوه‌های پیاده‌سازی ECMAScript نگاهی بیاندازیم، ۲ نوع با تنوع عجیباً غریبا داریم! Microsoft JScript و JavaScript. اولی اختصاصی Microsoft و دومی متعلق به Netscape که بعدها متن‌باز شد (پس از اهداء کد مرورگر به موزیلا). در حال حاضر Microsoft با اکراه فراوان JScript را کنار گذاشته و از JavaScript استفاده می‌کند. البته این به این معنی نبود که Microsoft از JScript استفاده نکرد. JScript به عنوان زبان Active Scripting Engine یا ActiveX استفاده شد؛ زبانی مانند VBScript و PerlScript و در کنار JScript، جاوااسکریپت به عنوان زبان برنامه‌نویسی سمت کلاینت وب استفاده شد.

از حواشی بگذریم، برسیم به اصل مطلب:

جاوااسکریپت، پیاده‌سازی ECMAScript برای استفاده مرحوم Netscape بود.

پس از خاکسپاری آن مرحوم و با ورود محبوب دل‌ها، فایرفاکس، تا حدودی مشکلات برطرف شد. سرتان را درد نیاورم، وارد تاریخچه فایرفاکس نمی‌شویم. از آن‌جا که محبوبیت روزافزون این مرورگر متن‌باز به توسعه‌دهندگان هم می‌افزود، موتور جاوااسکریپت آن یغتی SpiderMonkey هم به سرعت توسعه یافت. این توسعه که هم‌اکنون هم ادامه دارد بسیار به جامعه متن‌باز و همچنین جامعه جاوااسکریپت کمک کرده است.

پس کی به Node.js می‌رسیم؟ به‌زودی! کمی صبر داشته باشید!

اما جنگ‌های مرورگرها هم‌چنان ادامه داشت. تا این‌که مرورگرها این‌گونه شدند: IE9, Firefox 10, Google Chrome 16, Safari 5.1, Opera 11.60. نتیجه جنگ با ورود رقیب عوض شد! فایرفاکس در سیستم‌عامل های لیتوکس تقریباً یکه‌تاز میدان بود تا کروم با سرعت توسعه عجیب وارد شد! تقریباً هر یکی-دو ماه نسخه جدیدی از آن می‌آمد اما فایرفاکس هنوز در همان نسخه مانده بود! هر ماه به نسخه کروم یک عدد اضافه می‌شد ولی فایرفاکس به اعشار اضافه می‌کرد. کاربران زیادی به همین دلیل جذب کروم شدند. کروم در Render هم سرعت بالایی داشت (که از موتور Render سافاری به ارث برده بود). یکی از ابعاد سرعت آن، سرعت در اجرای جاوااسکریپت بود. موتور V8 به خوبی از پس اجرای هر کد سنگین جاوااسکریپت بر می‌آمد.

پس سرعت این موتورها چگونه به این‌جا رسید؟

Microsoft که خودش از نتایج Benchmarkهای موتور جاوااسکریپت Chakra عاجر شده بود، به سراغ راه حل بسیار مؤثری رفت: استفاده از JIT Compiler برای JavaScript. یعنی چه؟ یعنی ترجمه کدهای قابل فهم انسان، در زمان اجرا به کدهای ماشین(سخت‌افزاری) که پردازنده به آسانی می‌فهمد (این همان اتفاقی است که در زبان‌های دات‌نت رخ می‌دهد و باعث سریع بودن آن‌ها می‌شود). IE9 اولین نسخه ای بود که با این نسخه از موتور Chakra منتشر شد.

SpiderMonkey از نسخه ۳٫۵ فایرفاکس این‌گونه بود! وقتی موزیلا سراغ این روش رفت و کامپایلر TraceMonkey را نوشت، به گفته خودشان سرعت اجرا بین ۲۰ تا ۴۰ برابر افزایش داشت. اما باز هم راضی‌کننده نبود. اگر سریع به جلوتر برویم، می‌بینیم در نسخه ۱۱ این جزء کاملاً غایب است و کامپایلر دیگری به نام JägerMonkey جایش را گرفته. از مزایای این کامپایلر جدید این بود که کدهایی که TraceMonkey نمی‌توانست کامپایل کند، کامپایل می‌کرد. روش کار هم به طور کامل تغییر کرده بود. این کامپایلر از فایرفاکس ۴ به بعد وجود داشت اما تا فایرفاکس ۱۱، فقط زمانی استفاده می شد که TraceMonkey نمی‌توانست خروجی پایداری داشته باشد. اما بازهم موزیلا راضی نشد و IonMonkey را وارد بازی کرد. خروجی JägerMonkey، به صورت Bytecode بود که بازهم باید تفسیر می‌شذ. IonMonkey این Bytecodeها را به کد قابل فهم پردازنده یا کد ماشین (Native Code) کامپایل می‌کند. این باعث شد تا حتی روی پردازنده‌های ضعیف‌تر ARM که در گوشی‌های هوشمند استفاده می‌شوند نیز بتوان با سرعت بسیار بسیار بالا کدهای سنگین جاوااسکریپت و برنامه‌های کامپایل‌شده با Asm.js را اجرا کرد.

اما چگونه V8 سریع‌تر شد؟ V8 هم همین رویه را در پیش گرفت ولی به صورتی دیگر: این موتور بر اساس اسمبلر Strongtalk نوشته شده است. هم‌چنین تاکنون مفسر جاوااسکریپت آن ۳ بار بازنویسی کامل شده است که حتی کمک می‌کند برنامه‌های سنگین C و سی‌پلاس‌پلاس با Asm.js به جاوااسکریپت کامپایل شوند و روی موبایل با اشغال حافظه کم اجرا شوند که مزیت بسیار بزرگی برای این موتور است.

البته ناگفته نماند که هر ۳ این موتورها پابه‌پای یکدیگر در حال پیش‌روی هستند و با هم رقابت می‌کنند، هر چه باشد جنگ هنوز ادامه دارد!

برگردیم سراغ بحث خودمان: جاوااسکریپت در همه حوزه‌ها

بنیاد موزیلا که خودش را وقف توسعه وب کرده، کارمندی داشت به نام Kevin Dangoor. کوین پروژه‌ای برای ساخت مبنای جاوااسکریپت سمت‌سرور به نام ServerJS ایجاد کرد. او در مطلبی نوشت که: «چیزی که من اینجا توضیح می‌دهم، یک مشکل فنی نیست. فقط لازم است افرادی کنار هم جمع شوند و تصمیم بگیرند یک قدم رو به جلو بردارند و شروع به ساخت چیزی بزرگ‌تر و باحال‌تر با کمک هم کنند.» در آگوست ۲۰۰۹، پروژه به CommonJS تغییر نام داد تا کاربرد وسیع‌تر API‌های خود را نشان بدهد و یک اکوسیستم برپایه‌ی جاوااسکریپت بسازد. مشخصات و Specification‌های آن در یک پروسه باز تولید شد. بدین‌صورت که هر Specification پس از کامل شدن توسط چندین پیاده‌سازی CommonJS، به‌عنوان یک Final Specification ثبت می‌شد. لازم به‌ذکر است که با این که این پروژه با گروه TC39 از Ecma International (که تدوین‌کننده استانداردهای ECMAScript هستند) مرتبط نیست اما افرادی از این گروه در این پروژه دخالت دارند.

اما می‌رسیم به Node.js: از کجا شروع شد؟

Ryan Dahl در سال ۲۰۰۹، با دیدن نوار جریان (Progress bar) سایت Flickr به طراحی عجیبی برخورد کرد: مرورگر نمی‌دانست چقدر از یک پرونده را برای سرور فرستاده و برای این اطلاعات باید به سرور مراجعه می‌کرد! اما چرا لقمه را دور سرمان بچرخانیم؟ او راه ساده‌تری را ترجیح می‌داد.

او در کنفرانس JSConf اروپا در ۸ نوامبر ۲۰۰۹، پروژه Node.js را معرفی کرد. این پروژه موتور V8 گوگل را با یک چرخه رویداد (Event loop) و یک API سطح پایین ورودی/خروجی ناهمگام ترکیب می‌کرد. حضار به خاطر این پروژه ایستادند و او را تشویق کردند. از اینجا به بعد، این پروژه شکلی جدی به خودش گرفت و با جدیت تمام ادامه یافت.

در ژانویه ۲۰۱۰ یک مدیر بسته برای این محیط ارائه شد: npm. این مدیر بسته، از قالب ماژول‌های CommonJS استفاده کرد و مدیریت وابستگی‌ها (Dependency Management) را برای پروژه‌های Node.js ممکن کرد. npm یکی از عوامل مهم توسعه یافتن Node.js و بزرگتر شدن جامعه آن است.

اما تفاوت اصلی با زبان هایی مانند PHP در چیست؟

شاید فکر کنید کار آن مانند PHP و ASP است اما خیر! وقتی شما دستوری را در PHP اجرا کنید، تمام برنامه متوقف می‌شود تا آن دستور اجرا شود اما در Node هر دستوری که اجرا کنید (مخصوصاً دستورات ورودی/خروجی) باعث توقف برنامه نمی‌شود، بلکه شما Callbackهایی به آن دستور می‌دهید که دستوراتی که می‌خواهید پس از انجام کامل دستور قبلی انجام شوند، در آن‌ها انجام می‌دهید. با این شیوه، شما سرعت برنامه خود را به طور چشم‌گیری افزایش می‌دهید. مثلاً تمام برنامه متوقف نمی‌شود که یک فایل خوانده شود، بلکه خواندن در پس‌زمینه انجام می‌شود و برنامه به بقیه دستورات می‌رسد. فرض کنید صدها فایل بایستی باز شوند و پردازش شوند. شما می‌توانید تک-تک فایل‌ها را باز کنید(سری)، می‌توانید چندین فایل را همزمان باز کرده و اعمال لازم را روی آن‌ها انجام دهید. PHP و زبان‌هایی مانند آن فقط قادر به انجام اولی هستند ولی Node هر دو را امکان‌پذیر کرده است. روش اول در Node به‌سادگی روش دوم (که پیش‌فرض است و از اهداف اصلی پروژه) قابلیت پیاده‌سازی دارد.

این در اصل به خاطر non-blocking I/O، ورودی/خروجی ناهمگام و چرخه رویداد (Event loop) است که برنامه را از هزینه برای context switching در چندنخی بی‌نیاز می‌کند. استفاده از چرخه رویداد به جای نخ (Thread) و پروسه (Process)، قابلیت Scalability مثال‌زدنی به Node.js می‌دهد.

حمایت مالی از کجا تأمین می‌شود؟

این نکته را نزدیک بود از قلم بیندازم: شرکت Joyent (که اخیراً گروه سامسونگ آن را خریده است) اسپانسر و حامی این پروژه است. اگر این شرکت را نمی‌شناسید باید بگویم توییتر در روزهای آغازینش توسط این شرکت میزبانی می‌شده. تبحر این شرکت در رایانش ابری است.

Node.js، آینده‌ی جاوااسکریپت

از همان اوایل، Node.js را یکی از پیاده‌سازی‌های CommonJS می‌دانستند ولی Isaac Z. Schlueter نویسنده npm که از توسعه‌دهندگان اصلی است، نظری خلاف این دارد.
او می‌گوید: «رایان به من گفت که CommonJS را فراموش کنید، او مرده است! ما جاوااسکریپت سمت‌سرور هستیم! – که این حرف او هنوز یادم مانده است. من به یاد آوردم که چقدر از انرژی روحی ما در راهی صرف شد که به هیچ کس سودی نمی‌رساند و من آن موقع تصمیم گرفتم و پذیرفتم که Node تنها پیاده‌سازی سمت‌سرور جاوااسکریپت است که اهمیت دارد. عقاب که با مگس جنگ نمی‌کند!»
همچنین می‌گوید: «استانداردسازی وقتی هیچ پیاده‌سازی وجود ندارد، کمی ساده‌لوحی است»
در ادامه: «چیزهای خوبی هم از CommonJS به دست آمد. سیستم ماژولی که ما داریم، نسبت به پروپوزال «ماژول‌های قابل امن‌سازی(Securable Modules)» توسط Kris Kowal غیرقابل تمایز است.»
و همچنین:«شما می‌گویید ما همان راهی را می‌رویم که اینترنت اکسپلورر رفت! ما جنگ جاوااسکریپت سمت‌سرور (SSJS Wars) را برنده شده ایم، همان طور که پیش از این شده بودیم. در اصل، تنها دلیلی که کسی به دنبال دیگر پلتفرم های SSJS نمی‌رود، این است که موفقیت Node این روش اصولی را ثابت کرده است. ما در حال رقابت با پایتون، روبی و دیگر زبان‌های سمت‌سرور هستیم. Node، جاوااسکریپت سمت‌سرور است

اما الان: امروزه Node.js به حدی پیشرفت کرده که بسیاری از شرکت‌های بزرگ با وجود نوپا بودن این محیط نسبت به دیگر جایگزین‌ها مانند پایتون و روبی و امثالهم، Node را انتخاب کرده اند. غول‌هایی مانند eBay، Ge.tt، GoDaddy, LinkedIn, Microsoft, PayPal, ShutterStock, Netflix و Yahoo! از آن استفاده می‌کنند. حتی LinkedIn برنامه آندروید خود را برپایه Node ساخته و با وجود کم کردن ۷ عدد از سرورهایش، به سرعت ۲۰ برابر نسبت به زمان استفاده از روبی رسیده است! Netflix به جای گسترش عمودی (افزودن به تعداد سرورها) با استفاده از Node Container Layer به صورت افقی بزرگ‌تر می‌شود.

پروژه Node فقط با V8 کار نمی کند. Microsoft برای نشان دادن قدرت و سرعت نسل جدید موتور Chakra که متن‌باز هم شده، یک Fork از Node را با نوشتن لایه‌ای برای ترجمه APIهای V8 به Chakra به این موتور منتقل کرد.

یکی از توسعه‌دهندگان موزیلا هم برای این که نشان بدهد فایرفاکس از رقبا چیزی کم ندارد، همان لایه ترجمه کننده را با SpiderMonkey هماهنگ کرد.

کلام آخر

اگر تا الان آینده اسکریپت‌نویسی را در پایتون، روبی و… می‌دیدید باید به شما توصیه کنم که آن دوران گذشت و الان نوبتی هم که باشد، نوبت JavaScript است. امتحانش کنید، ضرر نمی‌کنید!

البته این نکته را هم باید بگویم که هر کسی را بهر کاری ساخته‌اند، Node را برای کارهای سنگین ورودی/خروجی. مثلاً در محاسبات سنگین ریاضی، مشخصاً زبان‌هایی مثل C یا Go یا Clojure از JavaScript سریع‌تر هستند ولی اگر می‌خواهید با ورودی/خروجی های سنگین سر و کله بزنید، Node.js انتخاب بسیار خوبی است.
همچنین از لحاظ زمان یادگیری، با توجه به این‌که اکثراً JavaScript بلد هستیم؛ پس یک پله جلو هستیم و فقط یاد گرفتن API را لازم داریم.
این در حالی است که به‌عنوان مثال، اگر بخواهید Clojure یاد بگیرید با Syntax بسیار متفاوت آن روبرو خواهید شد که از زبان‌های Lisp برگرفته شده است (البته طراحی زبان Clojure، بسیار عالی است، توصیه می‌کنم اگر وقت اضافی داشتید حتماً نگاهی به آن بیندازید).

لینک‌های مفید

وب‌سایت رسمی Node.js

از کجا شروع کنم؟ (به‌زودی مطلبی در این باره می‌نویسم)

منابع: ویکی‌پدیا و مخزن گیت‌هاب Node.js

پی‌نوشت

  1. من به io.js اشاره نکردم، اگر دوستان آزرده شدند به بزرگی خودشان ببخشند!
  2. ان‌شاءالله در نوشته‌های بعدی به شروع به کار با Node.js و استفاده از Electron و NW.js و علی‌الخصوص نحوه کار با Edge.js، به شرط حیات، اشاره کوچکی خواهم کرد. شاید به asm.js هم اشاره‌ای کردم…
  3. من، شخصاً تازه با Node.js آشنا شده‌ام و در همین مدت کم، تصمیم گرفتم PHP را کنار گذاشته و به Node.js کوچ کنم.
  4. هر اشکالی در نوشته دیدید، چه کوچک، چه بزرگ؛ بیان کنید. با ذکر نام شما و تشکر از شما نوشته را ویرایش می‌کنم 🙂