از طریق منوی جستجو مطلب مورد نظر خود در وبلاگ را به سرعت پیدا کنید
NodeJS چیست ؟ آشنایی اولیه با NodeJS
NodeJS چیست ، آشنایی مقدماتی با NodeJS
سرفصلهای مطلب
چیست ؟ Node.js در واقع یک محیط اجرایی متنباز سمت سرور برای کدهای JavaScript می باشد که که برمبنای موتور جاوا اسکریپت نسخه 8 (v8 ) توسعهیافته است. Node.js یک محیط اجرایی رویداد گرا (event driven) و non-blocking (asynchronous) است که همچنین مستقل از پلتفرم برای ساخت اپلیکیشنهای با قبالیت توسعه مداوم سمت سرور را فراهم می آورد
نودجیاس از مُدلی پیروی میکند که مبتنی بر رویداد (Event-driven) بوده و همچنین این مدل فرآیندهای ورودی و خروجی (I/O) را اصلاً بلاک نمیکند به طوری که استفاده از چنین مدلی موجب سَبکی و کارآمدی محیط اجرای نودجیاس شده است.
از Node.js میتوان برای ساخت انواع اپلیکیشنها از قبیل برنامههای خط فرمان، تحت وب، برنامه چت فوری، سرورهای Rest API و… استفاده کرد. البته این محیط اغلب برای ساخت برنامههای شبکه مانند سرورهای وب مشابه PHP، Java یا ASP.Net مورداستفاده قرار میگیرد.
Node.js در سال ۲۰۰۹ توسط Ryan Dahl ساخته شد. برای کسب اطلاعات بیشتر درباره تاریخچه Node.js میتوانید به سایت Wikipedia مراجعه کنید.
وبسایت رسمی Node.js: http://nodejs.org
صفحه گیت هاب Node.js: http://github.com/nodejs/node
کنفرانس جامعه کاربری Node.js: http://nodeconf.com
مزایای Node.js
۱- Node.js یک فریمورک متنباز و تحت لیسانس MIT است (لایسنس MIT یک مجوز برای نرمافزارهای آزاد است که اولین بار توسط انستیتو تحقیقاتی ماساچوست (MIT) ایجاد شد)
۲- از جاوا اسکریپت برای ساخت تمام بخشهای سمت سرور اپلیکیشن استفاده میکند.
۳- یک فریمورک سبک است که کمترین میزان ماژولها را دارد. ماژولهای دیگر بسته به نیاز هر پروژه به آن اضافه میشود.
۴- بهصورت پیشفرض غیر همزمان است، به همین خاطر از فریم ورکهای دیگر سریعتر عمل میکند.
۵- Node.js یک فریم ورک کراس پلتفرم است که میتواند روی سیستمعاملهای ویندوز، لینوکس و مکینتاش نصب شود.
تفاوت مدل پردازشی Node.js با دیگر سیستمها
Blocking I/O و Non-blocking I/O
به درخواستهای ورودی و خروجی از یک سیستم اشاره دارد و فرآیندهای گوناگونی را شامل میشود که از آن جمله میتوان به فرآیندهای به اصطلاح Read یا Write (به ترتیب به معنی خواندن و نوشتن) روی یکسری فایل سیستمی یا ارسال یک ریکوئست (درخواست) از نوع HTTP به یک API را نام برد. معمولاً چنین ریکوئستهایی زمانبَر هستند، لذا سیستم در هنگام دریافت درخواستهایی از جنس I/O، فانکشنهای دیگر را بلاک (مسدود) میکند تا بتواند در کمترین زمان ممکن پاسخ مناسب را به این درخواستها بدهد. برای درک بهتر این موضوع، سناریوی فرضی زیر را در نظر بگیرید:
یک درخواست از طرف سیستم به دیتابیس ارسال شده است تا اطلاعات کاربر شماره یک و همچنین کاربر شماره دو را دریافت کرده و آنها را در یک صفحه یا در کنسول چاپ کند. پاسخ به این ریکوئست کمی زمانبَر است اما هر دو درخواست برای چاپ دیتای کاربران میتوانند به صورت مستقل از هم و همزمان انجام شوند.
حال فرض کنید که ارسال ریکوئست و دریافت Response (پاسخ) از دیتابیس بر طبق فرآیند 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 را رجیستر میکنیم که در آن ایونتی به مدت 2000 میلیثانیه منتظر مانده و سپس مجدداً تابع Callback فراخوانی میشود.) پس از رجیستر کردن جفت Event-Callback، تابع (setTimeout(2000 از اِستک (پُشته) خارج میشود.
در مرحلهٔ بعد، تابع (setTimeout(0 به همین شیوه رجیستر میشود؛ حال دو ایپیآی Node داریم که منتظر اجرا هستند. تابع (setTimeout(0 بدون منتظر ماندن به Callback Queue (صف فراخوانی مجدد تابع) منتقل میشود و پس از 2000 ثانیه نیز تابع (setTimeout(2000 به صف Callback منتقل میشود. در صف Callback، این تابع صبر میکند تا پشته فراخوانی تابع خالی شود، زیرا تنها یک دستور میتواند در یک زمان اجرا شود و این در حالی است که فراخوانی توابع برای اجرا توسط Event Loop هندل میشود و در نهایت هم دستور ()console.log اجرا میشود و تابع ()main از پشته فراخوانی توابع خارج میشود.
در آنچه توضیح دادیم، Event Loop، که وظیفۀ هندل کردن توابع را بر عهده داشت، میبیند که پشته توابع خالی شده است اما صف Callback خالی نیست؛ بنابراین این حلقه توابعی را که برای اجرای مجدد فراخوانی شدهاند، بر اساس قانون FIFO از این پشته خارج کرده و وارد Call Stack میکند تا به ترتیب اجرا شوند (FIFO مخفف واژگان First In, First Out است و در ساختمان داده بدان معنا است که آنچه در ابتدا وارد پشته شود، ابتدا نیز خارج یا اجرا میگردد.)
در این بخش میخواهیم درباره مدل پردازشی Node.js صحبت کنیم و توضیح دهیم که چرا باید از Node.js در پروژههایمان بهره ببریم.
مدل سنتی دیگر زبانها در وب سرور
در مدل سنتی سرور وب هر درخواست توسط یک thread (رشته) از مخزن رشتهها مدیریت میشود. درصورتیکه هیچ رشتهای در مخزن وجود نداشته باشد، درخواست ارسالشده منتظر میماند تا یکی از رشتهها کارش تمام شود. رشتههای اختصاصی یک درخواست را اجرا میکند و تا زمانی که اجرای درخواست به اتمام نرسد و پاسخی به کلاینت ارسال نشود، آن رشته به مخزن برنمیگردد.
مدل پردازش Node.js
درخواستهایی که کاربران به برنامه Node.js ارسال میکنند متفاوت از درخواستهایی که به یک وب سرور سنتی ارسال میشوند، پردازش میشوند. کدهای برنامه Node.js تنها روی یک رشته و در یکروند پردازشی اجرا میشوند؛ درنتیجه منابع کمتری نسبت به فریم ورکهای دیگر موردنیاز خواهد بود. همه درخواستهایی که کاربران به برنامه تحت وب شما ارسال میکنند، تنها توسط یکرشته مدیریت میشود و همچنین همه عملیات ورودی و خروجی (I/O) یا عملیات طولانی که برای درخواستها موردنیاز است، بهصورت غیر همزمان اجرا میشوند. همچنین این رشته در حین انجام یک عملیات، قفل نمیشود و برای درخواستهای بعدی آزاد است. هنگامیکه یک عملیات غیر همزمان I/O کامل شد، درخواست بعدی پردازش میشود و پاسخ آن به کلاینت برگشت داده میشود. Node.js برای حلقه رویدادها از libev که از مخزن رشتههای C++ برای عملیات غیر همزمان I/O بهره میبرد استفاده میکند.
تصویر زیر مدل وب سرور غیر همزمان که توسط Node.js اجرا میشود را نمایش میدهد.
مدل پردازشی Node.js کارایی و مقیاسپذیری را با چند هشدار افزایش میدهد. Node.js برای برنامههایی که فشار زیادی روی CPU وارد میکنند مانند عملیات پردازش تصویر یا برنامههای سنگین دیگر مناسب نیست؛ چراکه این دستورها برای پردازش درخواستها به زمان زیادی نیاز دارند و در طی این مدت رشته را قفل میکنند.
درآمدی بر پَکیج مَنجر
NPM که مخفف واژگان Node Package Manager است، پَکیج مَنجر نودجیاس حاوی مجموعهای از لایبرریهایی است که با مشارکت کامیونیتی بزرگی از دولوپرهای جاوااسکریپت توسعه یافته است و پاسخی به نیازهای بسیاری از مسائل دولوپرها است.
آشنایی با ماژولهای پلتفرم Node.js
یک ماژول در نُود بلوکی از کد با قابلیت استفادهٔ مجدد است و اجرای این بلوک از کد بر روی کدهای دیگر تأثیر نمیگذارد. همچنین دولوپرها میتواند ماژولهای خود را نوشته و از آنها در برنامههای مختلف استفاده کنند و این در حالی است که خودِ پلتفرم نودجیاس نیز متشکل از مجموعۀ ماژولهای مختلفی است که دولوپرها میتوانند بدون نصب، آنها را مورد استفاده قرار دهند.
آشنایی با نحوۀ نوشتن Hello World در Node.js
برای این منظور، ابتدا یک فایل با نامی دلخواه همچون app.js ساخته و کد زیر را داخل آن مینویسیم:
console.log("Hello World!");
ترمینالِ سیستمعاملی که نُود رویش نصب است را باز کرده و دایرکتوری آن را به مسیری که فایل app.js در آن ذخیره شده، تغییر دهید. حال دستور زیر را اجرا کنید:
$ node app.js
بدین ترتیب، برنامهٔ سادهٔ Hello World در محیط نودیجیاس اجرا میشود!
درآمدی بر MEAN Stack
به طور کلی، هر زبان برنامهنویسی دارای فناوریهای وابسته به خود به منظور توسعهٔ سریعتر اپلیکیشنها است که از آن جمله میتوان به پکیجها، لایبرریها، فریمورکها و … برای هر زبان و محیط توسعهای اشاره کرد و این در حالی است که Node.js هم از این قاعده مستثنی نیست.
MEAN سرواژهای از حرف اول نام فناوریهای AngularJS، Express، MongoBD و NodeJS است؛ دقیقاً چیزی همچون اِستک LAMP که پکیجی از محیط توسعه (Linux)، وبسرور (Apache)، دیتابیس (MySQL) و زبان برنامهنویسی (PHP) است. در توضیح اِستک MEAN به نظر میرسد که به اندازهٔ کافی در مورد NodeJS تاکنون صحبت کردهایم و بهتر است بپردازیم به سه مورد دیگر که عبارتند از:
آشنایی با فریمورک Express
Express یک فریمورک سَبک است که برای توسعهٔ وب اپلیکیشن با استفاده از نُود به کار میرود. به عنوان نمونه سورسکد نوشته شده با این فریمورک داریم:
const express = require('express') const app = express() app.get('/', (req, res) => res.send('Hello World!')) app.listen(3000, () => console.log('Example app listening on port 3000!'))
آشنایی با فریمورک AngularJS
AngularJS یک فریمورک جاوااسکریپتی است که توسط کمپانی گوگل عرضه شده است که فیچرهای قابلتوجهی منجمله Two-way Data Binding در اختیار دولوپرها میگذارد و به نوعی میتوان گفت که سولوشن خوبی برای توسعهٔ فرانتاند است. به عنوان نمونه سورسکد نوشته شده با این فریمورک داریم:
angular.module('todoApp', []) .controller('TodoListController', function() { var todoList = this; todoList.todos = [ {text:'learn AngularJS', done:true}, {text:'build an AngularJS app', done:false}]; todoList.addTodo = function() { todoList.todos.push({text:todoList.todoText, done:false}); todoList.todoText = ''; }; todoList.remaining = function() { var count = 0; angular.forEach(todoList.todos, function(todo) { count += todo.done ? 0 : 1; }); return count; }; todoList.archive = function() { var oldTodos = todoList.todos; todoList.todos = []; angular.forEach(oldTodos, function(todo) { if (!todo.done) todoList.todos.push(todo); }); }; });
آشنایی با دیتابیس MongoDB
MongoDB یک دیتابیس از نوع NoSQL است که دیتا را به صورت فرمت جیسون ذخیره میسازد (در همین راستا، میتوانید به مقالهٔ درآمدی بر انواع مختلف دیتابیسهای NoSQL مراجعه نمایید.) به عنوان نمونه سورسکد نوشته شده با نودجیاس برای ارتباط با این دیتابیس داریم:
const MongoClient = require('mongodb').MongoClient; const assert = require('assert'); // Connection URL const url = 'mongodb://localhost:27017'; // Database Name const dbName = 'myproject'; // Use connect method to connect to the server MongoClient.connect(url, function(err, client) { assert.equal(null, err); console.log("Connected successfully to server"); const db = client.db(dbName); client.close(); });
در پایان، اگر علاقمند به فناوری Node.js هستید، میتوانید به تگ #نودجیاس در وبلاگ رسانگار مراجعه نمایید که مقالاتی مرتبط با این فناوری را شامل میگردد که برخی از مهمترین آنها عبارتند از: