تاریخ انتشار: چهارشنبه, ۹ مهر ۱۳۹۹، ۱۲:۰۰ ق.ظ نویسنده: محمدیان

حافظه میانگیر (Buffer)، در لغت به معنای حائل یا میانگر می‌باشد که در علوم مختلف به شکلی متفاوت به مفهوم یک حافظهٔ میانجی یا موقت بکار می‌رود.

بافر یا buffer عمومأ در علوم کامپیوتر و الکترونیک بیشتر به کار می‌رود که معمولأ اشاره به حافظه موقت یک سیستم دارد.

مثال:

buffer size = 1Mb به معنی این است که حافظه موقت این سیستم برابر با ۱ مگابایت می‌باشد
یا: اندازه حافظه موقت = 1Mb

مثلاً در شیمی محلول بافر محلولی است که ph را ثابت نگه می‌دارد، بنابراین به کمک این محلول می‌توان در مراحل گوناگون یک فرایند شمیایی ph را ثابت نگه داشته و آن را اندازه‌گیری نماییم. مدارهای بافر نیز در الکترونیک مفهومی نزدیک به این دارند. به این صورت که داده‌های سیگنال دریافتی را در خود نگهداری نموده و بر حسب نیاز به سیستم بعدی تحویل می‌دهند. مدارهای بافر به‌طور کلی به دو دسته آنالوگ و دیجیتال تقسیم می‌شوند.

معرفی بافرها

بافر به فضایی از حافظه اشاره دارد که از آن برای ذخیره‌سازی موقت داده‌ها استفاده می‌شود. یک بافر به طور معمول، بین دستگاه‌هایی که از لحاظ سرعت با یکدیگر هماهنگ نیستند، مورد استفاده قرار می‌گیرد، به طوری که این بافرها بدون اینکه به داده‌ها آسیب برسانند، می‌توانند عملیات در حال اجرا را در یک سرعت به خصوص نگهدارند. از بافرها در node.js، زمانی استفاده می‌شود که با یک جریان فایل (دقت کنید منظور از جریان یا stream، دنباله ایی متوالی از داده‌ها است) یا جریان tcp که عمدتاً دارای داده‌های باینری (binary) یا هشت‌تایی (octets) هستند، روبرو می‌شویم.

 

برای استفاده از بافرها نیاز به وارد کردن ماژول خاصی نیست، یک کللاس عمومی از آبجکت global است که در همه جای برنامه میتوانید از متودهای آن استفاده کنید.

برخی از متودهای مربوط به کار بافرها

Buffer.alloc(size[, fill[, encoding]])

Buffer.allocUnsafe(size)

Buffer.from(string[, encoding])

buf.compare(target[, targetStart[, targetEnd[, sourceStart[, sourceEnd]]]])

Buffer.concat(list)

buf.copy(target[, targetStart[, sourceStart[, sourceEnd]]])

buf.equals(otherBuffer)

buf.fill(value)

buf.indexOf(value)

buf.length

buf.slice([start[, end]])

()buf.toJSON

buf.toString([encoding[, start[, end]]])

 

تاریخ انتشار: جمعه, ۹ خرداد ۱۳۹۹، ۰۴:۰۴ ق.ظ نویسنده: محمدیان

آموزش MongoDB در Nod.js

همانطور که در موضوع قبلی مورد بحث قرار گرفت ، MongoDB یکی از محبوب ترین پایگاه داده ها است که به همراه Node.js. استفاده می شود. در طی این فصل خواهیم دید، چگونه می توانیم با بانک اطلاعاتی MongoDB ارتباط برقرار کنیم. چگونه می توانیم عملیات عادی خواندن داده از یک پایگاه داده و همچنین درج ، حذف و به روز کردن سوابق را در یک پایگاه داده MongoDB انجام دهیم. با توجه به هدف این فصل ، فرض کنید که داده های MongoDB زیر را در دسترس داریم.

نام بانک اطلاعاتی: EmployeeDB

نام مجموعه: Employee

Documents

{

{Employeeid : 1, Employee Name : Guru99},

{Employeeid : 2, Employee Name : Joe},

{Employeeid : 3, Employee Name : Martin},

}

1.ماژول NPM را نصب کنید

برای دسترسی به Mongo از داخل یک برنامه نود به یک درایور نیاز دارید. تعدادی درایور Mongo در دسترس است ، اما MongoDB از محبوب ترین آنها است. برای نصب ماژول MongoDB ، دستور زیر را اجرا کنید.

npm install mongodb

2. ایجاد و بستن اتصال به یک پایگاه داده MongoDB. قطعه کد زیر نحوه ایجاد و بستن اتصال به یک پایگاه داده MongoDB را نشان می دهد.

Node.js MongoDB Tutorial with Examples

توضیح کد:

1. اولین قدم شامل ماژول mongoose است که از طریق تابع require انجام می شود. پس از راه اندازی این ماژول ، می توانیم از توابع لازم موجود در این ماژول برای ایجاد اتصالات به پایگاه داده استفاده کنیم.

2. در مرحله بعد رشته اتصال خود را به پایگاه داده مشخص می کنیم. در رشته اتصال ، 3 مقدار کلیدی وجود دارد که منتقل می شوند.

  • اولین مورد “mongodb” است که مشخص می کند ما به یک پایگاه داده mongoDB وصل می شویم.
  • مورد بعدی “localhost” است به این معنی که ما به یک پایگاه داده در دستگاه محلی وصل می شویم.
  • مورد بعدی “EmployeeDB” است که نام پایگاه داده تعریف شده در پایگاه داده MongoDB ماست.

3.مرحله بعدی اتصال به بانک اطلاعاتی  است. تابع اتصال در URL ما گرفته می شود و امکان تعیین تابع برگشتی  را دارد. با باز شدن اتصال به دیتابیس فراخوانی می شود. این به ما فرصتی می دهد تا بدانیم که آیا اتصال بانک اطلاعاتی موفق بوده یا خیر.

4.در این تابع ، ما رشته ” Connection established ” را به کنسول می نویسیم تا نشان دهیم اتصال موفقیت آمیز ایجاد شده است.

5.در آخر ، ما اتصال را با استفاده از عبارت close می بندیم.

اگر کد بالا به درستی اجرا شود ، رشته ” Connected” همانطور که در شکل زیر نشان داده شده است بر روی کنسول نوشته خواهد شد.

Node.js MongoDB Tutorial with Examples

3. جستجوی داده ها در یک پایگاه داده MongoDB – با استفاده از درایور MongoDB می توانیم داده ها را از پایگاه داده MongoDB واکشی کنیم. در بخش زیر نحوه استفاده از درایور برای واکشی کلیه اسناد از مجموعه Employee در پایگاه داده EmployeeDB ما نشان داده خواهد شد. این مجموعه در پایگاه داده MongoDB ماست ، که شامل تمام اسناد مربوط به کارمندان (employee)است. هر سند دارای یک شناسه شی ( object id)، نام کارمند (Employee name)و شناسه کارمند (employee id)برای تعریف مقادیر سند است.

Node.js MongoDB Tutorial with Examples

var MongoClient = require('mongodb').MongoClient;

var url = 'mongodb://localhost/EmployeeDB';

MongoClient.connect(url, function(err, db) {

    var cursor = db.collection('Employee').find();

    cursor.each(function(err, doc) {

        console.log(doc);

    });

});

توضیح کد:

  1. در مرحله اول ، ما یک مکان نما را ایجاد می کنیم (مکان نما یک اشاره گر است که برای اشاره به رکوردهای مختلفی که از یک پایگاه داده بدست می آیند استفاده می شود. مکان نما برای تکرار از طریق رکوردهای مختلف در پایگاه داده استفاده می شود. در اینجا ما یک متغیر تعریف می کنیم به نام مکان نما ، که برای ذخیره نشانگر به سوابق گرفته شده از پایگاه داده استفاده می شود.) که به سوابق جمع آوری شده از مجموعه MongoDb اشاره می کند. ما همچنین می توانیم مجموعه “Employee” را برای واگذاری سوابق مشخص کنیم. تابع ()find  برای مشخص کردن اینکه می خواهیم همه اسناد را از مجموعه MongoDB بازیابی کنیم ، استفاده می شود.
  2. اکنون از طریق مکان نما خود تکرار می کنیم و برای هر سند در مکان نما می خواهیم یک تابع را اجرا کنیم.
  3. تابع ما این است که به سادگی می خواهیم محتوای هر سند را روی کنسول چاپ کنیم.

توجه: – همچنین می توان یک رکورد خاص را از یک پایگاه داده واکشی کرد. این می تواند با مشخص کردن شرایط جستجو در تابع ()find  انجام شود. به عنوان مثال ، فرض کنید اگر شما فقط می خواستید رکوردی را که نام employee با عنوان Guru99 دارد ، واکشی کنید ، می توانید این عبارت را به شرح زیر بنویسید.

	
var cursor=db.collection('Employee').find({EmployeeName: "guru99"})

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

خروجی:

Node.js MongoDB Tutorial with Examples

از خروجی ،

  • شما قادر خواهید بود به وضوح مشاهده کنید که تمام اسناد موجود در این مجموعه بازیابی می شوند. این کار با استفاده از روش ()find از  (connection (db mongoDBو تکرار آن از طریق تمام اسناد با استفاده از مکان نما امکان پذیر است.

4. درج اسناد در یک مجموعه – اسناد را می توان با استفاده از متد insertOne که توسط کتابخانه MongoDB تهیه شده است ، در یک مجموعه قرار دهید. قطعه کد زیر نشان می دهد که چگونه می توانیم یک سند را در یک مجموعه mongoDB وارد کنیم.

Node.js MongoDB Tutorial with Examples

var MongoClient = require('mongodb').MongoClient;

var url = 'mongodb://localhost/EmployeeDB';

MongoClient.connect(url, function(err, db) {

    db.collection('Employee').insertOne({

        Employeeid: 4,

        EmployeeName: "NewEmployee"

    });

});

توضیح کد:

  1. در اینجا ما از روش insertOne از کتابخانه MongoDB استفاده می کنیم تا یک سند را در مجموعه Employee وارد کنیم.
  2. ما در حال مشخص کردن جزئیات سند راجع به آنچه باید در مجموعه کارمندان وارد شود هستیم. اگر هم اکنون محتویات پایگاه داده MongoDB خود را بررسی کنید ، پرونده را با Employeeid 4 و EmployeeName از “NewEmployee” درج شده در مجموعه Employee پیدا خواهید کرد.

توجه: کنسول هیچ خروجی نشان نمی دهد زیرا رکورد در دیتابیس درج شده است و هیچ خروجی در اینجا قابل نمایش نیست.

برای بررسی اینکه داده ها به درستی در پایگاه داده درج شده است ، باید دستورات زیر را در MongoDB اجرا کنید.

  1. از EmployeeDB استفاده کنید
  2. db.Employee.find ({Employeeid}): 4

اولین جمله اطمینان می دهد که شما به پایگاه داده EmployeeDb متصل هستید. جمله دوم سوابق را که دارای شناسه کارمند 4 است را جستجو می کند.

5. به روزرسانی اسناد در یک مجموعه – اسناد را می توان در یک مجموعه با استفاده از کد updateOne از کتابخانه MongoDB به روز رسانی کرد. قطعه کد زیر نحوه به روزرسانی یک سند در یک مجموعه mongoDB را نشان می دهد.

Node.js MongoDB Tutorial with Examples

var MongoClient = require('mongodb').MongoClient;

var url = 'mongodb://localhost/EmployeeDB';

MongoClient.connect(url, function(err, db) {

    db.collection('Employee').updateOne({

        "EmployeeName": "NewEmployee"

    }, {

        $set: {

            "EmployeeName": "Mohan"

        }

    });

});

توضیح کد:

  1. در اینجا ما از روش “DeleteOne” از کتابخانه MongoDB استفاده می کنیم ، که برای حذف یک سند در یک مجموعه mongoDB استفاده می شود.
  2. ما در حال مشخص کردن شرایط جستجو از سندی هستیم که نیاز به حذف دارد. دراین مورد ، ما می خواهیم سندی را پیدا کنیم که دارای “EmployeeName ” از” NewEmployee”باشد و این سند را حذف کنیم.
  3. سپس می خواهیم مقدار EmployeeName سند را از “NewEmployee” به “Mohan” تنظیم کنیم.

اگر هم اکنون محتویات پایگاه داده MongoDB خود را بررسی کنید ، این پرونده را با Employeeid 4 و EmployeeName از “Mohan” حذف شده از مجموعه Employee پیدا خواهید کرد. برای بررسی اینکه داده ها به درستی در پایگاه داده به روز شده اند ، باید دستورات زیر را در MongoDB اجرا کنید.

  1. از EmployeeDB استفاده کنید
  2. ({ db.Employee.find ({Employeeid: 4

اولین جمله اطمینان می دهد که شما به پایگاه داده EmployeeDb متصل هستید. جمله  دوم تمام سوابق موجود در مجموعه کارمندان را جستجو و نمایش می دهد. در اینجا می توانید ببینید که آیا رکورد حذف شده است یا خیر.

6. حذف اسناد در یک مجموعه – اسناد را می توان با استفاده از روش “DeleteOne” تهیه شده توسط کتابخانه MongoDB در یک مجموعه حذف کرد. قطعه کد زیر نحوه حذف یک سند در یک مجموعه mongoDB را نشان می دهد.

Node.js MongoDB Tutorial with Examples

var MongoClient = require('mongodb').MongoClient;

var url = 'mongodb://localhost/EmployeeDB';

MongoClient.connect(url, function(err, db) {

    db.collection('Employee').deleteOne(

        {

            "EmployeeName": "Mohan"

        }

    );

});

توضیح کد:

1.در اینجا ما از روش “DeleteOne” از کتابخانه MongoDB استفاده می کنیم ، که برای حذف یک سند در یک مجموعه mongoDB استفاده می شود.

2. ما در حال مشخص کردن شرایط جستجو برای حذف  سندی هستیم که نیاز به حذف شدن دارد. در این مورد  ، ما می خواهیم سندی را پیدا کنیم که دارای EmployeeName ” از “Mohan”باشد و این سند را حذف کنیم.

اگر هم اکنون محتویات پایگاه داده MongoDB خود را بررسی کنید ، این پرونده را با “Employeeid 4 “و EmployeeName “از “Mohan” حذف شده از مجموعه “Employee “پیدا خواهید کرد.برای بررسی اینکه داده ها به درستی در پایگاه داده به روز شده اند ، باید دستورات زیر را در MongoDB اجرا کنید.

1.از EmployeeDB استفاده کنید.

2.()db.Employee.find

اولین جمله اطمینان می دهد که شما به پایگاه داده EmployeeDb متصل هستید. جمله دوم دوم تمام سوابق موجود در مجموعه کارمندان را جستجو و نمایش می دهد. در اینجا می توانید ببینید که آیا رکورد حذف شده است یا خیر.

 

ساختن یک برنامه گره اکسپرس با MongoDB برای ذخیره و سرویس محتوا

ساختن یک برنامه کاربردی با ترکیبی از Express و MongoDB امروزه کاملاً رایج است. هنگام کار با برنامه های کاربردی مبتنی بر وب JavaScript ، معمولاً در اینجا اصطلاح MEAN stack وجود دارد.

  • اصطلاح MEAN stack به مجموعه ای از فناوریهای مبتنی بر JavaScript است که برای توسعه برنامه های وب استفاده می شود.
  • MEAN مخفف MongoDB ، ExpressJS ، AngularJS وNod js می باشد.

از این رو ، همیشه خوب است بدانیم که چگونه Node.js و MongoDB با هم کار می کنند تا برنامه هایی را که با پایگاه داده های پشتیبان  تعامل دارند را ارائه دهند.

بیایید به یک مثال ساده از چگونگی استفاده از “express ” و “MongoDB” با هم نگاه کنیم. به عنوان مثال ما از همان مجموعه Employee در پایگاه داده MongoDB EmployeeDB استفاده خواهیم کرد. اکنون Express را برای نمایش داده ها در صفحه وب خود هنگام درخواست کاربر ، وارد می کنیم. هنگامی که برنامه ما روی Node.js اجرا می شود ، ممکن است نیاز به مرور آدرس اینترنتی http: // localhost: 3000 / Employeeid باشد.

با راه اندازی این صفحه ، تمام شناسه کارمند (employee id)موجود در مجموعه Employee نمایش داده می شود. بنابراین بیایید قطعه کد را در بخش هایی مشاهده کنیم که به ما امکان دستیابی به این هدف را می دهد.

مرحله 1) تمام کتابخانه هایی را که باید در برنامه های ما استفاده شوند تعریف کنید ، که در مورد ما کتابخانه MongoDB و Express است.

Node.js MongoDB Tutorial with Examples

توضیح کد:

  1. ما در حال تعریف کتابخانه ” Express ” خود هستیم که در برنامه ما استفاده خواهد شد.
  2. ما در حال تعریف کتابخانه ” Express ” خود هستیم که برای اتصال به پایگاه داده MongoDB در برنامه کاربردی ما استفاده می شود.
  3. در اینجا ما URL پایگاه داده خود را برای اتصال به آن تعریف می کنیم.
  4. سرانجام ، ما رشته ای را تعریف می کنیم که برای ذخیره کردن مجموعه شناسه کارمندان ما باید بعداً در مرورگر نمایش داده شود ، استفاده می شود.

مرحله 2) در این مرحله ، اکنون می خواهیم همه سوابق موجود در مجموعه ‘Employee’ خود را بدست آوریم و مطابق با آنها کار کنیم.

Node.js MongoDB Tutorial with Examples

توضیح کد:

  1. ما در حال ایجاد مسیری برای برنامه خود هستیم که “Employeeid” نام دارد. بنابراین هر وقت کسی به http: // localhost: 3000 / Employeeid برنامه ما مراجعه کند ، قطعه کد تعریف شده برای این مسیر اجرا خواهد شد.
  2. در اینجا ما تمام پرونده های موجود در مجموعه “Employee” خود را از طریق فرمان () db.collection(‘Employee’).findدریافت می کنیم. سپس ما این مجموعه را به متغیری به نام مکان نما اختصاص می دهیم. با استفاده از این متغیر مکان نما ، می توانیم تمام سوابق مجموعه را مرور کنیم.
  3. اکنون ما از تابع  ()cursor.eachبرای حرکت در سوابق مجموعه ما استفاده می کنیم. برای هر رکورد ، ما می خواهیم قطعه کد را تعریف کنیم که هنگام دستیابی به هر رکورد چه کاری باید انجام شود.
  4. سرانجام ، می بینیم که اگر رکورد برگشتی تهی نیست ، ما  “Employee “را از طریق دستور “item.Employeeid” می گیریم. بقیه ی کد فقط ساخت کد HTML مناسب است که به ما اجازه می دهد نتایج ما به درستی در مرورگر نمایش داده شود.

مرحله 3) در این مرحله ، ما می خواهیم که خروجی خود را به صفحه وب ارسال کنیم و برنامه خود را در پورت خاصی گوش دهیم.

Node.js MongoDB Tutorial with Examples

توضیح کد:

  1. در اینجا ما کل مطالبی را که در مرحله قبل ساخته شده است به صفحه وب ما ارسال می کنیم. پارامتر ‘res’ به ما اجازه می دهد تا به عنوان پاسخ ، مطالب را به صفحه وب خود ارسال کنیم.
  2. ما در حال ساخت کل برنامه  Nod js درپورت 3000 هستیم.

خروجی:

Node.js MongoDB Tutorial with Examples

از خروجی ،

  • به وضوح نشان می دهد که همه کارمندان ازمجموعه کارمندان بازیابی شدند. دلیل این امر این است که ما از درایور MongoDB برای اتصال به دیتابیس و بازیابی کلیه سوابق Employee استفاده می کنیم و متعاقباً از “Express” برای نمایش رکوردها استفاده می کنیم.

در اینجا کد مرجع شما وجود دارد:

var express = require('express');

var app = express();

var MongoClient = require('mongodb').MongoClient;

var url = 'mongodb://localhost/EmployeeDB';

var str = ""; app.route('/Employeeid').get(function(req, res)

    {

        MongoClient.connect(url, function(err, db) {

            var cursor = db.collection('Employee').find();

            //noinspection JSDeprecatedSymbols

            cursor.each(function(err, item) {

                if (item != null) {

                    str = str + "    Employee id  " + item.Employeeid + "</br>";

                }

            });

            res.send(str);

            db.close();

        });

    });


var server = app.listen(3000, function() {});

توجه: cursor.each ممکن است براساس نسخه درایور MongoDB شما منسوخ شود. برای دور زدن مشکل می توانید // noinspection JSDeprecatedSymbols را قبل از cursor.each اضافه کنید. روش دیگر ، می توانید از ForEach استفاده کنید. در زیر کد نمونه با استفاده از forEach وجود دارد.

var express = require('express');

var app = express();

var MongoClient = require('mongodb').MongoClient;

var url = 'mongodb://localhost/EmployeeDB';

var str = "";

app.route('/Employeeid').get(function(req, res) {

   MongoClient.connect(url, function(err, db) {

       var collection = db.collection('Employee');

       var cursor = collection.find({});

       str = "";

       cursor.forEach(function(item) {

           if (item != null) {

                   str = str + "    Employee id  " + item.Employeeid + "</br>";
           }

       }, function(err) {

           res.send(str);

           db.close();

          }

       );

   });

});

var server = app.listen(8080, function() {});

خلاصه

  • Node.jsدر رابطه با پایگاه داده های NoSQL برای ساخت بسیاری از برنامه های وب امروزی مدرن استفاده می شود. برخی از پایگاههای داده رایج مورد استفاده MySQL و MongoDB هستند.
  • یکی از ماژول های متداول که برای کار با بانکهای اطلاعاتی MongoDB استفاده می شود ، ماژول ای به نام ‘MongoDB’ است. این ماژول از طریق مدیر بسته Node نصب شده است.
  • با استفاده از ماژول MongoDB می توان سوابق مربوط به سوابق موجود در یک مجموعه را پرس و جو کرد و به روزرسانی معمولی ، حذف و درج عملیات را انجام داد.
  • درنهایت ، یکی از شیوه های مدرن، استفاده از فریم ورک Express به همراه MongoDB برای ارائه برنامه های امروزی است. فریم ورک Express می تواند از داده های برگرداننده درایور MongoDB استفاده کند و داده ها را در صفحه وب به کاربر نشان دهد.

تاریخ انتشار: جمعه, ۹ خرداد ۱۳۹۹، ۰۳:۴۳ ق.ظ نویسنده: محمدیان

آموزش جریان داده یا Streams در Node.js : کار با Filestream و Pipes در Node.js

Filestream در Node.js

Node به عنوان مکانیسم انتقال داده از جریانهای گسترده استفاده می کند. به عنوان مثال ، هنگامی که شما با استفاده از تابع console.log ، چیزی را به کنسول منتقل می کنید ، در واقع از یک جریان برای ارسال اطلاعات به کنسول استفاده می کنید. Node.js همچنین قابلیت جابجایی داده ها از پرونده ها را دارد تا بتوان آنها را به طور مناسب خواند و نوشت. اکنون به نمونه ای از چگونگی استفاده از جریان ها برای خواندن و نوشتن از پرونده ها خواهیم پرداخت. برای این مثال باید مراحل زیر را دنبال کنیم.

مرحله 1) یک پرونده با نام data.txt ایجاد کنید که داده های زیر را دارد. بگذارید فرض کنیم این پرونده در درایو D دستگاه محلی ما ذخیره شده است.

  • آموزش در Node.js
  • مقدمه
  • مناسبت ها
  • مولدها
  • اتصال داده
  • استفاده از جاسمین

مرحله 2) کد مربوطه را بنویسید که از خواندن داده ها از پرونده استفاده می کند.

Node js Streams Tutorial: Filestream, Pipes

var fs = require("fs");
var stream;
stream = fs.createReadStream("D://data.txt");

stream.on("data", function(data) {
    var chunk = data.toString();
    console.log(chunk);
});


1.ما ابتدا ماژول های ‘fs’ را نیاز داریم که  که شامل تمام عملکردهای مورد نیاز برای ایجاد جریان ها است.توضیح کد: 

2.در مرحله بعدی ما با استفاده از متد createReadStream ، یک جریان قابل خواندن ایجاد می کنیم . به عنوان ورودی ، ما محل فایل data.txt خود را می دهیم.

3.تابع steam.on یک کنترل کننده رویداد است و در آن ، ما اولین پارامتر را به عنوان “داده” مشخص می کنیم. این بدان معناست که هر زمان داده ها  از پرونده وارد جریان می شوند ،یک تابع برگشتی  را اجرا می کنند. در این مورد ، ما در حال تعریف یک تابع برگشتی هستیم که 2 مرحله اساسی را انجام خواهد داد. اولین مورد ، تبدیل داده های خوانده شده از پرونده به عنوان رشته است. مورد دوم ارسال رشته تبدیل شده به عنوان خروجی به کنسول است.

4.ما هر قطعه از داده ها را که از جریان داده خوانده می شود ، گرفته و آن را به یک رشته تبدیل می کنیم.

5.سرانجام ، ما خروجی هر قطعه تبدیل شده به رشته را به کنسول ارسال می کنیم.

خروجی:

Node js Streams Tutorial: Filestream, Pipes

  • در صورت اجرای صحیح کد ، خروجی فوق را در کنسول مشاهده خواهید کرد. این خروجی همان پرونده موجود در پرونده data.txt خواهد بود.

 

نوشتن فایل بصورت stream در نود جی اس

به همین روش ، که ما یک جریان فایل بصورت Stream ایجاد می کنیم ، می توانیم یک جریان نوشتن فایل بصورت Stream نیز  در یک پرونده ایجاد کنیم. بیایید ابتدا یک پرونده خالی و بدون محتوا به نام data.txt ایجاد کنیم. فرض کنیم این پرونده در درایو D کامپیوتر ما قرار گرفته است. کد زیر نشان می دهد که چگونه می توانیم داده را به پرونده بنویسیم.

Node js Streams Tutorial: Filestream, Pipes

var fs = require("fs");
var stream;
stream = fs.createWriteStream("D://data.txt");

stream.write("Tutorial on Node.js")
stream.write("Introduction")
stream.write("Events")
stream.write("Generators")
stream.write("Data Connectivity")
stream.write("Using Jasmine")

توضیح کد:

  1. ما در حال ایجاد یک جریان قابل نوشتار با استفاده از روش – createWriteStream هستیم. به عنوان ورودی ، ما محل فایل txt خود را می دهیم.
  2. در مرحله بعدی از متد stream.write برای نوشتن سطرهای مختلف متن به فایل متنی استفاده کردیم. stream، از نوشتن این داده ها به پرونده data.txt  مراقبت میکند.

اگر پرونده data.txt را باز کنید ، اکنون داده های زیر را در پرونده مشاهده خواهید کرد.

  • آموزش در Node.js
  • مقدمه
  • رویدادها
  • مولدها
  • اتصال داده
  • استفاده از جاسمین

 

pipes در Node.js

در برنامه های Node ، می توان جریانها را با استفاده از روش ()pipe که دو آرگومان را میگیرد به یکدیگر وصل کرد.

  • یک جریان قابل نوشتار ضروری که به عنوان مقصد برای داده ها عمل می کند و
  • یک شیء اختیاری که برای انتقال گزینه ها استفاده می شود.

اگر می خواهید داده ها را از یک پرونده به پرونده دیگر انتقال دهید ، نمونه بارز استفاده از pipes است. بنابراین بیایید نمونه ای از چگونگی انتقال داده ها از یک پرونده به پرونده دیگر با استفاده از لوله ها را ببینیم.

مرحله 1) یک پرونده با نام datainput.txt ایجاد کنید که داده های زیر را دارد. بگذارید فرض کنیم این پرونده در درایو D دستگاه محلی ما ذخیره شده است.

  • آموزش در Node.js
  • مقدمه
  • رویدادها
  • مولدها
  • اتصال داده
  • استفاده از جاسمین

مرحله 2) یک پرونده  خالی به نام dataOutput.txt ایجاد کنید و آن را در درایو D دستگاه محلی خود قرار دهید.

مرحله 3) برای انجام انتقال داده از پرونده datainput.txt به پرونده dataOutput.txt کد زیر را بنویسید.

Node js Streams Tutorial: Filestream, Pipes

var fs = require("fs");
var readStream = fs.createReadStream("D://datainput.txt");
var writeStream = fs.createWriteStream("D://dataOutput.txt");
readStream.pipe(writeStream);

توضیح کد:

  1. ما ابتدا یک پرونده “readstream” را در پرونده txt خود ایجاد می کنیم که شامل تمام داده های مورد نیاز برای انتقال به پرونده جدید است.
  2. سپس ما نیاز به ایجاد “Writestream” به پرونده dataOutput.txt که فایل خالی ما است و مقصد انتقال داده ها از پرونده datainput.txt است.
  3. سپس از دستور pipes برای انتقال اطلاعات از جریان خواندن به جریان نوشتن استفاده می کنیم. دستور pipes ، تمام داده های وارد شده به خواندن را می گیرد ، و آن را به سمت نوشتن متن سوق می دهد.

اگر اکنون پرونده  dataOutput.txt را باز کرده اید ، تمام داده های موجود در پرونده datainput.txt را مشاهده خواهید کرد.

 

رویدادها یا Events در Node.js

Events یا رویدادها یکی از مفاهیم کلیدی در Node.js  هستند و بعضی اوقات به Node.js به عنوان یک چارچوب رویداد محور گفته می شود. اصولاً یک رویداد اتفاقی است که رخ می دهد. به عنوان مثال ، اگر یک اتصال به یک پایگاه داده برقرار شود ، رویداد ارتباط بانک اطلاعاتی آغاز می شود. برنامه نویسی  رویداد محور، ایجاد توابعی است که باعث شروع رویدادهای خاص  می شوند.

بیایید به یک مثال ساده برای تعریف یک رویداد در Node.js بزنیم .ما می خواهیم رویدادی به نام ‘data_received’ ایجاد کنیم. با شروع این رویداد ، متن ” “data received” ” به کنسول ارسال می شود.

Node js Streams Tutorial: Filestream, Pipes

var events = require('events');
var eventEmitter = new events.EventEmitter();
eventEmitter.on('data_received', function() {
    console.log('data received succesfully.');
});

eventEmitter.emit('data_received');

توضیح کد:

  1. با استفاده از تابع require ، ماژول ” events ” را درج کنید. با استفاده از این ماژول ، می توانید رویدادهایی را در nod .js ایجاد کنید.
  2. یک فرستنده ی رویدادهای جدید ایجاد کنید. این مورد برای پیوند دادن این رویداد استفاده می شود ، که در این مورد “data_received” به یک تابع برگشتی است که در مرحله 3 تعریف شده است.
  3. ما یک تابع رویداد محور را تعریف می کنیم که می گوید اگر در صورت بروز رویداد “data_received” ما باید متن “data_received” را درخروجی کنسول قراردهیم.
  4. در آخر ، ما با استفاده از تابع  eventEmiter.emit یک اسلحه دستی از رویداد خود داریم. این رویداد data_received را شروع می کند.

هنگام اجرای برنامه ، متن “data received ” مطابق شکل زیر به کنسول ارسال می شود.

Node js Streams Tutorial: Filestream, Pipes

 

انتشار رویدادها یا Emitting Events در Node.js

هنگام تعریف رویدادها ، روشهای مختلفی برای وقایع وجود دارد که می توان از آنها استفاده کرد. این مبحث تمرکزش را  بر جزئیات هر یک از آنها می پردازد.

  1. یک بار اجرا کننده رویداد

بعضی اوقات ممکن است شما علاقه مند باشید فقط در اولین باری که رویداد اتفاق می افتد  واکنش نشان دهید. در این مواقع می توانید از روش ()once استفاده کنید. بیایید ببینیم که چگونه می توانیم از متد once  برای اجرای کننده ی رویداد استفاده کنیم.

Node js Streams Tutorial: Filestream, Pipes

توضیح کد:

  1. در اینجا ما از روش “once” استفاده می کنیم تا بگوییم که برای رویداد “data_received” ، تابع برگشتی فقط باید یک بار انجام شود.
  2. در اینجا ما به طور دستی رویداد “data_received” را شروع می کنیم.
  3. وقتی رویداد “data_received” دوباره شروع شود ، این بار هیچ اتفاقی نخواهد افتاد. این به دلیل اولین قدم است که در آنجا گفتیم که این رویداد فقط یک بار می تواند آغاز شود.

اگر کد به درستی اجرا شود ، خروجی موجود در کنسول با موفقیت “data_received” خواهد بود. این پیام فقط یک بار در کنسول ظاهر می شود.

  1. بازرسی شنوندگان رویداد

در هر نقطه از عمر خود ، یک پخش کننده رویداد می تواند صفر یا بیشتر شنوندگان داشته باشد که به آن متصل هستند. شنوندگان برای هر نوع رویداد می توانند از چند طریق مورد بازرسی قرار گیرند. اگر شما فقط می خواهید تعداد شنوندگان پیوست را تعیین کنید ، به دنبال روش  () EventEmitter.listenerCount نباشید.

(توجه: شنوندگان مهم هستند زیرا برنامه اصلی باید بداندکه آیا شنوندگان در پرواز به یک رویداد اضافه می شوند ، در غیر این صورت این برنامه با نقص کار می کند زیرا شنوندگان اضافی فراخوانی می شوند.)

Node js Streams Tutorial: Filestream, Pipes

 

توضیح کد:

  1. ما در حال تعریف یک نوع eventEmitter هستیم که برای استفاده از روش های مرتبط با رویداد لازم است.
  2. سپس ما در حال تعریف شیئی به نام emitter هستیم که برای تعریف کننده های رویداد ما استفاده می شود.
  3. ما در حال ایجاد 2 رویداد هستیم که اساساً هیچ کاری انجام نمی دهند. این فقط به عنوان مثال ساده برای نشان دادن نحوه عملکرد روش listenerCount می باشد.
  4. حال هنگامی که از رویداد listenerCount در رویداد data_received ما استفاده می کنید ، تعداد شنوندگان این رویداد را در پرونده کنسول ارسال می کنید.
  5. اگر کد به درستی اجرا شود ، مقدار 2 در کنسول نشان داده می شود.

       3. رویداد newListener

هر بار که یک کنترل کننده رویداد جدید ثبت شود ، پخش کننده رویداد، یک رویداد newListener را منتشر می کند. این رویداد برای شناسایی مجریان رویداد جدید استفاده می شود. شما معمولاً هنگام تخصیص منابع یا انجام برخی اقدامات برای هر اداره کننده رویداد جدید ، معمولاً از رویداد newListener استفاده می کنید.

Node js Streams Tutorial: Filestream, Pipes

var events = require('events');
var eventEmitter = events.EventEmitter;
var emitter = new eventEmitter();
emitter.on("newListener", function(eventName, listener) {
    console.log("Added listener for " + eventName + " events");
});
emitter.on('data_received', function() {});
emitter.on('data_received', function() {});

توضیح کد:

  1. ما در حال ایجاد یک کنترل کننده ی رویداد جدید برای رویداد ‘newListener’ هستیم. بنابراین هر زمان که یک کنترل کننده رویداد جدید ثبت شود ، متن ” “Added listener for” + نام رویداد در کنسول نمایش داده می شود.
  2. در اینجا ما در حال نوشتن متن کنسول  “Added listener for ” + نام رویداد برای هر رویداد ثبت شده هستیم.
  3. ما در حال تعریف 2 عامل کنترل کننده رویداد برای رویداد “data_received” هستیم.

اگر کد بالا به درستی اجرا شود ، متن زیر در کنسول نشان داده می شود. فقط نشان می دهد که کنترل کننده رویداد “newListener” دو بار شروع  شده است.

شنوندگان برای رویدادهای data_received اضافه شدند.

شنوندگان برای رویدادهای data_received اضافه شدند.

خلاصه

  • جریان داده در Node.js برای خواندن و نوشتن داده ها از دستگاه های ورودی-خروجی استفاده می شود. Node.js از کتابخانه ‘fs’ برای ایجاد جریانهای قابل خواندن و نوشتاری در پرونده ها استفاده می کند. از این جریان ها می توان برای خواندن و نوشتن داده ها از پرونده ها استفاده کرد.
  • برای اتصال چندین جریان به هم می توان از pipes استفاده کرد. یکی از متداول ترین نمونه ها ، انتقال جریان خواندن و نوشتن به یکدیگر برای انتقال داده ها از یک پرونده به پرونده دیگر است.
  • Node.js اغلب به عنوان یک چارچوب رویداد محور نیز نشان داده می شود ، و تعریف رویدادها در Node.js. بسیار آسان است. توابع قابل تعریف هستند که به این رویدادها پاسخ می دهند.
  • رویدادها همچنین روش هایی برای پاسخ به رویدادهای کلیدی را در معرض نمایش قرار می دهند. به عنوان مثال ، ما شاهد کنترل رویداد () once هستیم که می تواند مورد استفاده قرار گیرد تا اطمینان حاصل شود که یک تابع برگشتی فقط یک بار در هنگام شروع یک رویداد انجام می شود.

تاریخ انتشار: پنجشنبه, ۱ خرداد ۱۳۹۹، ۱۲:۱۸ ق.ظ نویسنده: محمدیان

برای دسترسی به هر صفحه وب باید یک وب سرور داشته باشید. یک سرور قادر است تا درخواست های HTTP را دریافت کرده و با کمک کد ها شما، پاسخ را به کاربر ارسال کند.

به عنوان مثال در زبان asp.net وب سرور IIS مورد استفاده قرار می گیرد و برای اجرای کد های جاوا یا PHP وب سرورهایی مانند apache وجود دارد.

نود.جی اس به شما این امکان را می دهد تا وب سرور خودتان را با چند خط کد ساده ایجاد کنید و درخواست های HTTP را به صورت ناهمگام (asynchronous) پاسخ دهید.

شما می توانید از وب سرورهای IIS و آپاچی نیز برای اجرای کدهای Node.js استفاده کنید گرچه این کار پیشنهاد نمی شود.

ساخت یک وب سرور با استفاده از Node.js

نود.جی اس به سادگی قادر است تا یک وب سرور را برای مدیریت درخواست های ورودی راه اندازی کند.

مثال زیر نشان می‌دهد که شما چگونه می توانید یک وب سرور را در فایلی به نام server.js به کمک Node.js بسازید و اجرا کنید:

var http = require('http'); // 1 - Import Node.js core module

var server = http.createServer(function (req, res) {   // 2 - creating server

    //handle incomming requests here..

});

server.listen(5000); //3 - listen for any incoming requests

console.log('Node.js web server at port 5000 is running..')

فصل ۱۰ – مثال ۱ (فایل server.js)

در مثال بالا ما ماژول http را به کمک فانکشن require() در فایل ایمپورت کرده ایم.

ماژول http یک ماژول هسته ای برای Node.js است پس نیازی نیست که آن را به کمک این NPM نصب کنید.

قدم بعدی این است که متود createServer() تعبیه شده درون http را با پارامتر های req و res صدا بزنیم، این دو متغیر حاوی اطلاعات درخواست (request) و پاسخ (response) خواهند بود. مقدار بازگردانده شده را به متغیر server انتساب خواهیم داد، زیرا همچنان با این سرور ایجاد شده کار داریم.

در نهایت ما باید متود listen() از متعلقات متود createServer() را صدا بزنیم. این کار با کد server.lister(port) انجام می شود. port در اینجا عدد پورتی که به اپلیکیشن می خواهید اختصاص دهید خواهد بود.

پورت اصلی سرور ها ۸۰ است و نیاز به تایپ کردن ندارد، اگر پورت چیزی غیر از ۸۰ باشد باید با دو نقطه پس از آدرس در مرورگر وارد شود. مثلا localhost:8080 باید وارد شود ولی localhost:80 را می شود به صورت localhost استفاده کرد.

کد server.listen(5000) به نود.جی اس می گوید که به پورت ۵۰۰۰ سرور توجه کند. مثلا هر درخواستی که به آدرس localhost:5000 ارسال شد را دریافت کند.

در مثال بالا ما همچنان به سیستم نگفته ایم که در صورتی که درخواست را دریافت کرد چه پاسخی به آن بدهد.

برای اجرای کد های بالا فقط کافی است در محیط ترمینال یا CMD کد node server.js را تایپ کنید.

پس از اجرای کد پاسخ Node.js web server at port 5000 is running.. از سیستم دریافت خواهد شد.

حالا که ساختن یک وب سرور را آموختید بگذارید به شما نشان دهیم که چگونه می توانید پاسخ درخواست ها را نیز ارسال کنید. اگر پاسخی به درخواست ها ارسال نکنید کاربر در صورت ارسال درخواست در مرورگر صفحه ای مشاهده نخواهد کرد.

مدیریت درخواست های HTTP در Node.js

در متود http.createServer() دو پارامتر response و request تعبیه شده است که برای مدیریت پاسخ های HTTP مورد استفاده قرار می گیرند.

آبجکت request حاوی اطلاعاتی در مورد درخواست ارسال شده به سرور است. اطلاعاتی مانند آدرس درخواستی، header های ارسالی با درخواست و data در این آبجکت وجود دارد.

ابجکت response را می توان برای ارسال پاسخ متناسب به درخواست استفاده کرد.

مثال زیر نشان می‌دهد که شما چگونه می توانید یک درخواست HTTP را با کمک Node.js مدیریت کنید:

var http = require('http'); // Import Node.js core module

var server = http.createServer(function (req, res) {   //create web server
    if (req.url == '/') { //check the URL of the current request
        
        // set response header
        res.writeHead(200, { 'Content-Type': 'text/html' }); 
        
        // set response content    
        res.write('This is home Page.');
        res.end();
    
    }
    else if (req.url == "/student") {
        
        res.writeHead(200, { 'Content-Type': 'text/html' });
        res.write('This is student Page.');
        res.end();
    
    }
    else if (req.url == "/admin") {
        
        res.writeHead(200, { 'Content-Type': 'text/html' });
        res.write('This is admin Page.');
        res.end();
    
    }
    else
        res.end('Invalid Request!');

});

server.listen(5000); //6 - listen for any incoming requests

console.log('Node.js web server at port 5000 is running..')

فصل ۱۰ – مثال ۲ (فایل server.js)

در مثال بالا req.url استفاده شده است تا اپلیکیشن آدرس درخواستی کاربر را تشخیص دهد.

برای ارسال پاسخ متناسب با درخواست کاربر ابتدا ما باید Header مناسب را با متود writeHead() به پاسخ اضافه کنیم و سپس با استفاده از متود write() متنی را بر روی صفحه چاپ کنیم.

در نهایت در هنگامی که Node.js با متود end() برخورد می کند اطلاعات را نشان خواهد داد.

پس از اجرای کد پاسخ Node.js web server at port 5000 is running.. از سیستم دریافت خواهد شد.

اکنون می توانید در مرورگر خود آدرس http://localhost:5000 را باز کرده و متن This is home page را مشاهده کنید

اگر شما آدرس http://localhost:5000/student را در مروگر باز کنید نتیجه زیر را مشاهده خواهید کرد:

در حال حاضر هر درخواست دیگری به سرور نتیجه ” Invalid Request” خواهد داشت.

ارسال پاسخ JSON به درخواست های HTTP در Node.js

مثال زیر نشان می دهد چگونه می توانید پاسخ JSON به درخواست های HTTP ارسال کنید:

var http = require('http'); 

var server = http.createServer(function (req, res) {   
   
    if (req.url == '/data') { //check the URL of the current request
            res.writeHead(200, { 'Content-Type': 'application/json' });
            res.write(JSON.stringify({ message: "Hello World"}));  
            res.end();  
    }
});

server.listen(5000);

console.log('Node.js web server at port 5000 is running..')

فصل ۱۰ – مثال ۳ (فایل server.js)

اگر بعد از اجرای مثال بالا، آدرس http://localhost:5000/data را در مرورگر باز کنید، با جمله Hello World در قالب JSON مواجه خواهید شد.

 

 

تاریخ انتشار: پنجشنبه, ۱ خرداد ۱۳۹۹، ۱۲:۱۱ ق.ظ نویسنده: محمدیان

خواندن فایل ها با استفاده از ماژول fs در Node.js

شما می توانید با استفاده از متود fs.readFile() یک فایل را به صورت ناهمگام بخوانید.

سینتکس زیر نحوه تعریف یک متد خواندن فایل را با استفاده از ماژول fs در Node.js نشان می دهد:

fs.readFile(fileName [,options], callback)

توضیح پارامترهای سینتکس بالا:

filename: آدرس کامل یا همان full path فایلی که قرار است خوانده شود. (در قالب رشته)

options: این پارامتر می‌تواند یک رشته و یا Object باشد که حاوی encoding و flag است. encoding پیشفرض برابر utf8 و flag برابر r است. (بعدا بیشتر توضیح می دهیم)

callback: یک فانکشن است که دو پارامتر err و fd را دریافت می کند. پارامتر err حاوی پیغام های خطا و پارامتر fd حاوی اطلاعات درون فایل خواهد بود.

مثال زیر نشان می دهد که چگونه می توانیم اطلاعات فایلی به نام TestFile.txt که در کنار اسکریپت ما قرار دارد را به صورت ناهمگام بخوانیم:

var fs = require('fs');

fs.readFile('TestFile.txt', function (err, data) {
                    if (err) throw err;

    console.log(data);
});

فصل ۱۱ – مثال ۱

هنگامی که از ناهمگام بودن نحوه خواندن اطلاعات از فایل ها صحبت می کنیم منظورمان این است که ابتدا نرم افزار شروع به خواندن اطلاعات فایلها می کند و پس از اتمام فعالیت خود فانکشن callback را صدا می زند.

در مثال بالا پارامتر err در صورتی که فایل موجود نباشد حاوی مقداری خواهد بود. در غیر این صورت پارامتر data اطلاعات فایل را دارا می باشد.

به عنوان مثال در کنار فایل js مثال بالا، فایلی ایجاد کنید به نام TextFile.txt که حاوی متن Hello word باشد.

سپس در محیط ترمینال یا CMD با زدن دستور node server.js، فایل اصلی را اجرا کنید.

در صورتی که مشکلی وجود نداشته باشد باید متن Hello word را در محیط کنسول مشاهده کنید.

همچنین می توانید با استفاده از متود fs.readFileSync() به صورت همگام اطلاعات را بخوانید.

مثال زیر نشان می دهد که چگونه می توانید با استفاده از متود fs.readFileSync() یک فایل را به صورت همگام یا synchronous بخوانید:

var fs = require('fs');

var data = fs.readFileSync('TestFile.txt', 'utf8');
console.log(data);

فصل ۱۱ – مثال ۲

نوشتن بر روی فایل با استفاده از ماژول fs در Node.js

نوشتن بر روی یک فایل به همان سادگی خواندن فایل ها در Node.js است. با استفاده از متود fs.writeFile() قادر هستید تا بر روی یک فایلی که در حال حاضر موجود است اطلاعاتی را بنویسید.

سینتکس نگارش متود fs.writeFile() به شرح زیر است:

fs.writeFile(filename, data[, options], callback)

توضیح پارامترهای سینتکس بالا:

filename: آدرس کامل یا همان full path فایلی که قرار است بر روی آن متنی شود. (در قالب رشته)

data: اطلاعاتی که باید درون فایل نوشته شود.

options: این پارامتر می‌تواند یک رشته و یا Object باشد که حاوی encoding و flag است. encoding پیشفرض برابر utf8 و flag برابر r است. (بعدا بیشتر توضیح می دهیم)

callback: یک فانکشن است که دو پارامتر err و fd را دریافت می کند. پارامتر err حاوی پیغام های خطا و پارامتر fd حاوی اطلاعات درون فایل خواهد بود.

مثال زیر یک فایل به نام test.txt ایجاد خواهد کرد و به صورت ناهمگام متن “Hello World” را درون آن خواهد نوشت:

var fs = require('fs');

fs.writeFile('test.txt', 'Hello World!', function (err) { 
                        if (err)
        console.log(err);
                        else
        console.log('Write operation complete.');
});

فصل ۱۱ – مثال ۳

توجه داشته باشید که مثال بالا، اگر فایل موجود باشد، هر چیزی که درون این فایل از قبل موجود باشد را پاک خواهد کرد و سپس متن جدید را جایگزین آن خواهد کرد.

اگر می خواهید که اطلاعات درون یک فایل پاک نشود و اطلاعات جدید بعد از اطلاعات حال حاضر درون این فایل قرار بگیرد می توانید از متود fs.appendFile() استفاده کنید.

مثال زیر نشان می دهد که چگونه می توانید جمله “Hello Word!” را بعد از هر چیزی که درون فایل test.txt وجود دارد بنویسید:

var fs = require('fs');

fs.appendFile('test.txt', 'Hello World!', function (err) { 
                        if (err)
        console.log(err);
                        else
        console.log('Append operation complete.');
});

فصل ۱۱ – مثال ۴

باز کردن یک فایل با ماژول fs در Node.js

به صورت آلترناتیو نسبت به متود های بالا شما میتوانید از متود fs.open() در باز کردن یک فایل برای خواندن یا نوشتن بر روی آن استفاده کنید.

سینتکس متود fs.open() به شرح زیر است:

fs.open(path, flags[, mode], callback)

توضیح پارامترهای سینتکس بالا:

path: آدرس کامل یا همان full path فایلی که قرار است باز شود. (در قالب رشته)

flag: پرچم عملیاتی که قرار است بر روی فایل صورت پذیرد. (در ادامه آموزش جدول کل پرچم های ممکن را می توانید مشاهده کنید)

mode: انتخاب حالت باز کردن فایل برای خواندن، نوشتن یا خواندن-نوشتن فایل.

callback: یک فانکشن است که دو پارامتر err و fd را دریافت می کند. پارامتر err حاوی پیغام های خطا و پارامتر fd حاوی اطلاعات درون فایل خواهد بود.

پرچم های قابل استفاده درون فانکشن های مرتبط با فایل در Node.js:

پرچم توضیحات
r یک فایل را برای خواندن باز می کند، اگر فایل موجود نباشد ارور ایجاد می شود.
r+ یک فایل را برای خواندن و نوشتن باز می کند، اگر فایل موجود نباشد ارور ایجاد می شود.
rs فایل را برای خواندن همگام باز می کند.
rs+ یک فایل را برای خواندن و نوشتن باز می کند، این فلگ به سیستم اعلام می کند که این کار را به صورت همگام انجام دهد.
w یک فایل را برای نوشتن باز می کند. اگر فایل موجود نباشد آن را می سازد، اگر فایل موجود باشد آن را ابتدا خالی می کند.
wx مثل w عمل می کند، اما اگر path موجود باشد ارور ایجاد خواهد شد.
w+ یک فایل را برای نوشتن و نوشتن باز می کند. اگر فایل موجود نباشد آن را می سازد، اگر فایل موجود باشد آن را ابتدا خالی می کند.
wx+ مثل w+ عمل می کند، اما اگر path موجود باشد ارور ایجاد خواهد شد.
a یک فایل را برای اضافه کردن چیزی به انتهای آن باز می کند.
ax مثل a عمل می کند، اما اگر path موجود باشد ارور ایجاد خواهد شد.
a+ یک فایل را برای اضافه کردن چیزی به انتهای آن و خواندن آن باز می کند. اگر فایل موجود نباشد ایجاد خواهد شد.
ax+ مثل a+ عمل می کند، اما اگر path موجود باشد ارور ایجاد خواهد شد.

مثال زیر یک فایل از قبل موجود را باز می کند و اطلاعات درون آن را می خواند:

var fs = require('fs');

fs.open('TestFile.txt', 'r', function (err, fd) {
    
                            if (err) {
                            return console.error(err);
    }
    
                            var buffr = Buffer.alloc(1024);
    
    fs.read(fd, buffr, 0, buffr.length, 0, function (err, bytes) {
       
                            if (err) throw err;
            
                            // Print only read bytes to avoid junk.
                            if (bytes > 0) {
            console.log(buffr.slice(0, bytes).toString());
        }
        
                            // Close the opened file.
        fs.close(fd, function (err) {
                            if (err) throw err;
        });
    });
});

فصل ۱۱ – مثال ۵

حذف فایل با ماژول fs در Node.js

حذف فایل ها در Node.js بسیار ساده انجام می شود اما در مورد حذف حتما مراقب باشید.

شما می توانید با استفاده از متود fs.unlink() یک فایل را از سیستم حذف کنیم.

سینتکس استفاده از متود fs.unlink() برای حذف فایلها در Node.js به شرح زیر است:

fs.unlink(path, callback);

مثال زیر نشان می دهد که چگونه می توانید یک فایل را در نود حذف کنید:

var fs = require('fs');

fs.unlink('test.txt', function () {
    
    console.log('deleting operation complete.');

});

فصل ۱۱ – مثال ۶

متود های قابل استفاده در ارتباط با فایل ها در Node.js

fs.readFile(fileName [,options], callback)

اطلاعات درون یک فایل که از قبل موجود است را می خواند.

fs.writeFile(filename, data[, options], callback)

اطلاعاتی را در یک فایل می نویسد. اگر فایل موجود باشد اطلاعات اولیه را پاک کرده و سپس متن را درون آن می نویسد و اگر فاییل موجود نباشد، ابتدا آن را ایجاد می کند و سپس اطلاعات را درون آن قرار می دهد.

fs.open(path, flags[, mode], callback)

فایل را برای خواندن و نوشتن باز می کند.

fs.rename(oldPath, newPath, callback)

یک فایل که از قبل وجود دارد را تغییر نام می دهد.

fs.chown(path, uid, gid, callback)

عملیات chown را به صورت نا همگام انجام می دهد.

fs.stat(path, callback)

آبجکت fs.stat را باز می گرداند که حاوی اطلاعات مهمی از فایل درخواستی است.

fs.link(srcpath, dstpath, callback)

به صورت ناهمگام فایل ها را لینک می کند.

fs.symlink(destination, path[, type], callback)

به صوت ناهمگام Symlink برای فایل ایجاد می کند.

fs.rmdir(path, callback)

یک دایکتوری که از قبل وجود دارد را تغییر نام می دهد.

fs.mkdir(path[, mode], callback)

یک دایرکتوری جدید را ایجاد می کند.

fs.readdir(path, callback)

محتوای یک دایرکتوری درخواستی را می خواند.

fs.utimes(path, atime, mtime, callback)

timestamp یک فایل را تغییر می دهد.

fs.exists(path, callback)

مشخص می کند آیا فایل درخواستی وجود دارد یا نه.

fs.access(path[, mode], callback)

قابلیت دسترسی کاربر به فایلی را مشخص می کند.

fs.appendFile(file, data[, options], callback)

مقداری متن جدید به انتهای فایلی که از قبل وجود دارد اضافه می کند.

تاریخ انتشار: پنجشنبه, ۱ خرداد ۱۳۹۹، ۱۲:۰۷ ق.ظ نویسنده: محمدیان

برنامه نویسی Node.js با ماژول ها، برنامه نوشته شده را بسیار خوانا تر می کند. معمولا ماژول فقط یک کار خاص را انجام می دهند و بار ها در طول اپلیکیشن مورد قابل استفاده قرار می گیرند. یک ماژول معمولا حاوی یک عملیات خاص می باشد که به صورت مستقل قادر به انجام هدف خود است.

در فصل قبلی ما دیدیم که چگونه می توانید با استفاده از module.exports یک ماژول لوکال را اکسپورت کنید (برای استفاده در تمامی اپلیکیشن، ماژول را معرفی کنید). اکنون می خواهیم نشان دهیم که چگونه می توانید ماژول های مختلف از انواع مختلف را با استفاده از module.exports اکسپورت کنید.

module.exports یا exports دو شی  خاص هستند که در تمامی فایلهای جاوا اسکریپت Node.js به طور پیش فرض وارد می شوند.

در module.exports درواقع کلمه module یک متغیر است که اشاره به ماژولی که درون آن هستیم دارد و کلمه exports یک شی است که این ماژول را برای کل اپلیکیشن به عنوان یک ماژول در دسترس معرفی خواهد کرد.

هر چیزی که شما به module.exports اختصاص دهید به عنوان یک ماژول به اپلیکیشن معرفی خواهد شد.

معرفی مقدار Literal به عنوان ماژول (خروجی گرفتن از Literal)

همانطور که در بالا اشاره کردیم exports یک شی یا همان object است. پس این شی هر چیزی که به آن اختصاص دهید را در اختیار کل اپلیکیشن قرار خواهد داد. پس در نتیجه اگر شما یک مقدار رشته را به این شیء اختصاص دهید آن رشته به عنوان یک ماژول به اپلیکیشن معرفی خواهد شد.

مثال زیر نشان می‌دهد که شما چگونه می توانید یک مقدار رشته را به عنوان یک ماژول به سیستم معرفی کنید. بهتر است فایلی به نام Message.js بسازید و فقط کد زیر را درون آن قرار دهید:

module.exports = 'Hello world';

//or

exports = 'Hello world';

فصل ۸ – مثال ۱ (فایل Message.js)

اکنون ماژولی که ساختید را درون فایل app.js با فانکشن require() فراخوانی کنید. مانند مثال زیر:

var msg = require('./Messages.js');

console.log(msg);

فصل ۸ – مثال ۱ (فایل app.js)

اگر دقت کنید قبل از اسم فایل نقطه و اسلش قرار گرفته است. ./ درواقع به همان فولدر که درون آن هستیم اشاره دارد. البته برای استفاده از ماژول های هسته ای نیاز به مشخص کردن path یا همان مسیر فایل ها ندارید.

برای اجرای مثال بالا می توانید در محیط ترمینال یا CMD دستور node app.js را تایپ کرده و اینترنت بزنید. (دقت کنید که در محیط ترمینال ابتدا باید با دستور cd به مکانی که فایل را ساخته اید نقل مکان کنید.)

معرفی Object به عنوان ماژول (خروجی گرفتن از Object)

exports یک object است پس می توانید به آن صفت یا متود اختصاص دهید.

مثال زیر نشان می دهد که شما چگونه می توانید یک رشته را به عنوان صفت به یک آبجکت اختصاص دهید و object را اکسپورت کنید. بهتر است فایلی به نام Message.js ساخته و کد زیر را درون آن کپی کنید:

exports.SimpleMessage = 'Hello world';

//or

module.exports.SimpleMessage = 'Hello world';

فصل ۸ – مثال ۲ (فایل Message.js)

در مثال بالا ما صفت SimpleMessage را به شی export اختصاص داده ایم.

شما اکنون می توانید ماژول ساخته شده را در فایل app.js به شکل زیر مورد استفاده قرار دهید:

var msg = require('./Messages.js');

console.log(msg.SimpleMessage);

فصل ۸ – مثال ۲ (فایل app.js)

در مثال بالا فانکشن require() آبجکت { SimpleMessage : 'Hello World'} را باز می گرداند. پس شما می توانید با استفاده از نام متغیر اختصاص داده شده به این ماژول، صفت های درون آن را صدا بزنید. مانند: msg.SimpleMessage

مثال بالا را با استفاده از node app.js در ترمینال اجرا کنید.

به همین سبک بالا می توانید یک فانکشن را به همراه آبجکت اکسپورت کنید.

مثال زیر نشان می دهد که شما چگونه می توانید فانکشن لاگ را به همراه یک شی به عنوان یک ماژول اکسپورت کنید، این کد ها را در فایل Log.js ذخیره کنید:

module.exports.log = function (msg) { 
    console.log(msg);
};

فصل ۸ – مثال ۳ (فایل Log.js)

مثال بالا در واقع آبجکت { log : function(msg){ console.log(msg); } } را در هنگام استفاده از require() باز خواهد گرداند. پس شما می توانید با استفاده از نام متغیر اختصاص داده شده به متود های درونی آن دسترسی پیدا کنید.

به مثال زیر توجه کنید، این کد ها محتویات فایل app.js است:

var msg = require('./Log.js');

msg.log('Hello World');

فصل ۸ – مثال ۳ (فایل app.js)

مثال بالا را با استفاده از node app.js در ترمینال اجرا کنید.

شما می توانید به روش زیر نیز یک object را به عنوان ماژول اکسپورت کنید. بهتر است فایلی به نام data.js ساخته و متن زیر را درون آن کپی کنید:

module.exports = {
    firstName: 'James',
    lastName: 'Bond'
}

فصل ۸ – مثال ۴ (فایل data.js)

برای فراخوانی این ماژول می توانید در فایل app.js کد زیر را استفاده کنید:

var person = require('./data.js');
console.log(person.firstName + ' ' + person.lastName);

فصل ۸ – مثال ۴ (فایل app.js)

مثال بالا را با استفاده از node app.js در ترمینال اجرا کنید.

معرفی فانکشن به عنوان ماژول (خروجی گرفتن از Function)

به روش زیر شما قادر هستید تا یک فانکشن را به عنوان یک ماژول export کنید. پیشنهاد می شود فایلی به نام Log.js ساخته و کد زیر را درون آن کپی کنید:

module.exports = function (msg) { 
    console.log(msg);
};

فصل ۸ – مثال ۵ (فایل Log.js)

اکنون می توانید با کد زیر ماژول را درون فایل app.js فراخوانی کنید:

var msg = require('./Log.js');

msg('Hello World');

فصل ۸ – مثال ۵ (فایل app.js)

در مثال بالا متغیر msg به یک عبارت عملیاتی یا همان Function Expression تبدیل خواهد شد. پس شما می توانید با استفاده از پرانتز بعد از نام متغیر، فانکشن را اجرا کنید.

مثال بالا را با استفاده از node app.js در ترمینال اجرا کنید.

معرفی فانکشن به عنوان یک کلاس

در زبان جاوا اسکریپت می توان با یک فانکشن به عنوان یک کلاس برخورد کرد.

مثال زیر نشان می دهد که شما چگونه می توانید یک فانکشن را مانند یک کلاس export کنید. این محتویات را درون فایل Person.js کپی کنید:

module.exports = function (firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.fullName = function () { 
        return this.firstName + ' ' + this.lastName;
    }
}

فصل ۸ – مثال ۶ (فایل Person.js)

ماژول ساخته شده بالا را می توان به روش زیر در فایل app.js مورد استفاده قرار داد:

var person = require('./Person.js');

var person1 = new person('James', 'Bond');

console.log(person1.fullName());

فصل ۸ – مثال ۶ (فایل app.js)

مثال بالا را با استفاده از node app.js در ترمینال اجرا کنید تا نتیجه James Bond را همان جا مشاهده کنید.

بارگذاری ماژول ها از پوشه های دیگر

برای بارگذاری ماژول ها، در هر پوشه ای که باشند، در فانکشن require() فقط کافی است تا از full path یا همان آدرس کامل فایل استفاده کنید.

به عنوان مثال اگر فایلی که در آن از فانکشن require() استفاده کرده اید ماژولی که در فولدر utility قرار داده شده باشد را فراخوانی می کند، به این صورت عمل کنید:

var log = require('./utility/Log.js');

فصل ۸ – مثال ۷ (فایل app.js)

در مثال بالا نقطه . مشخص می کند که فولدر utility کنار همین فایلی که در حال اجرای require هست، وجود دارد.

بارگذاری ماژول ها فقط با نام پوشه ای که درون آن قرار دارند

Node.js به شما اجازه می دهد تا فقط با اشاره به نام فولدری که ماژول درون آن قرار دارد، ماژول را فراخوانی کنید. البته مراحل کمی متفاوت است.

مانند مثال زیر که شبیه مورد بالا عمل می کند:

var log = require('./utility');

فصل ۸ – مثال ۸ (فایل app.js)

این مرحله اول کار بود. هنگامی که از نام پوشه استفاده می کنید، Node.js بنا را بر این می گذارد که درون این پوشه یک پکیج وجود دارد. برای اینکه شما Node.js را برای درک بهتر این پکیج راهنمایی کنید، باید فایلی به نام package.json را درون پوشه utility قرار دهید. با محتویات زیر:

{
    "name" : "log",
    "main" : "./Log.js"
}

فصل ۸ – مثال ۸ (فایل package.json)

درواقع این کلمه کلیدی “main” مشخص می کند که فایل اصلی که پکیج ما به آن اشاره دارد کدام فایل است و همچنین نام پکیج را کلمه کلیدی “name” مشخص می کند.

اگر فایل package.json وجود نداشته باشد، Node.js به صورت اتوماتیک فایل index.js را به عنوان فایل ماژول در نظر می گیرد.

منبع: نتران

تاریخ انتشار: پنجشنبه, ۱ خرداد ۱۳۹۹، ۱۲:۰۳ ق.ظ نویسنده: محمدیان

Node.js به برنامه نویسان اجازه می دهد تا رویداد های دلخواه خود را ایجاد کنند و هر بار که خواستند آنها را به اجرا درآورند. ماژول events حاوی کلاس EventEmitter است که می‌تواند رویداد ها را ایجاد کرده و آنها را مدیریت کند. فصل سیزدهم آموزش نود.جی اس نتران، به نحوه استفاده از ماژول events برای به اجرا درآوردن یک رویداد اختصاص دارد.

مثال زیر نشان می‌دهد که شما چگونه می‌توانید از کلاس EventEmitter برای ساخت یک رویداد دلخواه استفاده کنید:

// get the reference of EventEmitter class of events module
var events = require('events');

//create an object of EventEmitter class by using above reference
var em = new events.EventEmitter();

//Subscribe for FirstEvent
em.on('FirstEvent', function (data) {
    console.log('First subscriber: ' + data);
});

// Raising FirstEvent
em.emit('FirstEvent', 'This is my first Node.js event emitter example.');

 

در مثال بالا ما ابتدا این ماژول events را ایمپورت کرده و سپس یک شی از کلاس EventEmitter ایجاد می کنیم.

سپس با استفاده از متود on() یک فانکشن مدیریت کننده برای رویداد مورد نظر تعریف می کنیم.

فانکشن on() نام رویداد را به عنوان پارامتر اول و فانکشن مدیریت در صورت رخداد رویداد را به عنوان پارامتر دوم دریافت می کند.

فانکشن emit() یک رویداد را اجرا می کند. در پارامتر اول نام رویداد را باید به این فانکشن بدهید و به عنوان پارامتر دوم می توانید اطلاعات اضافی را به رویداد انتقال دهید.

همچنین شما می توانید با استفاده از متود addListener() در صورت ایجاد رخداد مورد نظر یک فانکشن را اجرا کنید. مانند مثال زیر:

var emitter = require('events').EventEmitter;

var em = new emitter();

//Subscribe FirstEvent
em.addListener('FirstEvent', function (data) {
    console.log('First subscriber: ' + data);
});

//Subscribe SecondEvent
em.on('SecondEvent', function (data) {
    console.log('First subscriber: ' + data);
});

// Raising FirstEvent
em.emit('FirstEvent', 'This is my first Node.js event emitter example.');

// Raising SecondEvent
em.emit('SecondEvent', 'This is my second Node.js event emitter example.');

متود های مهم کلاس EventEmitter

emitter.addListener(event, listener)

این متود یک listener برای یک رویداد خاص به آخر آرایه listener ها اضافه می کند. توجه کنید که بررسی اینکه آیا این listener از قبل وجود دارد یا نه انجام نمی شود.

emitter.on(event, listener)

این متود یک listener برای یک رویداد خاص به آخر آرایه listener ها اضافه می کند. توجه کنید که بررسی اینکه آیا این listener از قبل وجود دارد یا نه انجام نمی شود. از این متود به جای متود addListener می توان استفاده کرد.

emitter.once(event, listener)

این متود فقط برای یک بار، یک رویداد را به اجرا در می آورد.

emitter.removeListener(event, listener)

یک listener را برا یک رویداد خاص حذف می کند.

emitter.removeAllListeners([event])

تمام listener ها را برای یک رویداد خاص حذف می کند.

emitter.setMaxListeners(n)

به طور پیشفرض EventEmitter ها بعد از اضافه کردن ۱۰ عدد listener پیغام هشدار چاپ می کنند.

emitter.getMaxListeners()

مقدار نهایی تعداد listener های ممکن برای یک eventEmiter را باز می گرداند. چه با emitter.setMaxListeners(n) ست شده باشد، چه به صورت پیشفرض

emitter.listeners(event)

یک کپی از آرایه listener ها باز می گرداند.

emitter.emit(event[, arg1][, arg2][, …])

یک رویداد خاص را به اجرا در می آورد.

emitter.listenerCount(type)

تعداد listener هایی که به این نوع رویداد واکنش نشان می دهند را از می گرداند.

روش های متداول استفاده از EventEmitter ها

دو روش متداول برای استفاده از EventEmitter ها در Node.js وجود دارد:

  • بازگرداندن EventEmitter در یک فانکشن
  • توسعه دادن کلاس EventEmitter

بازگرداندن EventEmitter در یک فانکشن

فانکشن سازنده آبجکتی از کلاس EventEmitter را باز می گرداند که برای مدیریت رویداد ها استفاده شده است.

این آبجکت EventEmitter را می توان برای مشترک شدن در رویداد ها استفاده کرد. (یعنی هنگامی که رویداد رخ داد، فانکشنی اجرا شود)

به عنوان مثال به کد زیر توجه کنید:

var emitter = require('events').EventEmitter;

function LoopProcessor(num) {
    var e = new emitter();
    
    setTimeout(function () {
        
        for (var i = 1; i <= num; i++) {
            e.emit('BeforeProcess', i);
            
            console.log('Processing number:' + i);
            
            e.emit('AfterProcess', i);
        }
    }
    , 2000)
    
    return e;
}
var lp = LoopProcessor(3);

lp.on('BeforeProcess', function (data) {
    console.log('About to start the process for ' + data);
});

lp.on('AfterProcess', function (data) {
    console.log('Completed processing ' + data);
});

فصل ۱۳ - مثال ۳

پاسخ اجرای کد بالا چنین خواهد بود:

About to start the process for 1 
Processing number:1
Completed processing 1
About to start the process for 2
Processing number:2
Completed processing 2
About to start the process for 3
Processing number:3
Completed processing 3

در فانکشن LoopProcessor() ابتدا ما یک شی از کلاس EventEmitter ایجاد کرده ایم رویدادهای 'BeforeProcess' و 'AfterProcess' را emit کرده ایم. (emit کردن یعنی اجرا یا انتشار یک رویداد)

در نهایت در این فانکشن با Object ساخته شده از کلاس EventEmitter را باز می گردانیم.

پس ما قادر هستیم با کمک متغیر lp که به فانکشن LoopProcessor() اشاره دارد و اکنون آبجکتی از کلاس EventEmitter است در رویدادها مشترک شویم. اشتراک در رویدادها به کمک فانکشن on() انجام می شود.

به جای فانکشن on() از فانکشن addListener() نیز می توان استفاده کرد.

توسعه دادن کلاس EventEmitter

در این روش مدیریت رویدادها باید در یک فانکشن سازنده کلاس EventEmitter را توسعه دهید و رویدادها را در آن مدیریت کنید.

به مثال زیر توجه کنید:

var emitter = require('events').EventEmitter;

var util = require('util');

function LoopProcessor(num) {
    var me = this;

    setTimeout(function () {
        
        for (var i = 1; i <= num; i++) {
            me.emit('BeforeProcess', i);
            
            console.log('Processing number:' + i);
            
            me.emit('AfterProcess', i);
        }
    }
    , 2000)
        
    return this; 
}

util.inherits(LoopProcessor, emitter)

var lp = new LoopProcessor(3);

lp.on('BeforeProcess', function (data) {
    console.log('About to start the process for ' + data);
});

lp.on('AfterProcess', function (data) {
    console.log('Completed processing ' + data);
});

پاسخ اجرای کد بالا چنین خواهد بود:

About to start the process for 1 
Processing number:1
Completed processing 1
About to start the process for 2
Processing number:2
Completed processing 2
About to start the process for 3
Processing number:3
Completed processing 3 

در مثال بالا ما فانکشن LoopProcessor را با کلاس EventEmitter به وسیله متود util.inherits() گسترش داده ایم. پس this در مثال بالا به کلاس EventEmitter اشاره دارد.

 

منبع : نتران netrun.ir

تاریخ انتشار: چهارشنبه, ۳۱ ارديبهشت ۱۳۹۹، ۱۱:۱۵ ب.ظ نویسنده: محمدیان

حلقه Event یکی از مهم‌ترین جنبه‌های جاوا اسکریپت است که باید درک شود. در این بخش از مقالات آموزش Node.js جزییات دقیق طرز کار جاوا اسکریپت با «نخ» (Thread) منفرد و شیوه مدیریت تابع‌های ناهمگام را مورد بررسی قرار می‌دهیم.

به طور کلی، در اغلب مرورگرها یک حلقه Event روی هر برگه مرورگر وجود دارد که موجب می‌شود هر پردازشی مجزا باشد و از مسدودسازی کل مرورگر در نتیجه یک پردازش سنگین یا حلقه بی‌نهایت جلوگیری شود. این محیط چندین حلقه Event همزمان را مدیریت می‌کند تا برای نمونه فراخوانی‌های API را مدیریت کند. بدین ترتیب Web Workers در حلقه رویداد خودشان اجرا می‌شوند. شما به صورت عمده باید در مورد این نگران باشید که کد روی یک حلقه رویداد منفرد اجرا خواهد شد و در هنگام نوشتن کد این ذهنیت جلوگیری از مسدودسازی را مداوماً داشته باشید.

مسدودسازی حلقه Event

هر کد جاوا اسکریپتی که بازگرداندن کنترل به حلقه event را بیش از حد طول بدهد، موجب مسدود شدن اجرای کد جاوا اسکریپت در صفحه خواهد شد و حتی ممکن است نخ UI را مسدود کند. در این حالت کاربر دیگر نمی‌تواند روی چیزی کلیک کند و یا کارهایی مانند اسکرول و نظایر آن انجام دهد.

تقریباً همه کارهای ابتدایی I/O در جاوا اسکریپت غیر مسدودکننده هستند. بنابراین درخواست‌های شبکه، عملیات فایل سیستم Node.js و مواردی از این دست همگی غیر مسدودکننده هستند. مسدودکننده بودن یک استثنا است و به همین دلیل جاوا اسکریپت به طور عمده بر مبنای callback-ها کار می‌کند. البته در نسخه‌های اخیر تمرکز بیشتر روی promises و async/await انتقال یافته است.

پشته فراخوانی

پشته فراخوانی یک صف LIFO به معنی «ورودی آخر، خروجی اول» (Last In ،First Out) است. حلقه Event به طور پیوسته پشته فراخوانی را بررسی می‌کند تا ببیند آیا هیچ تابعی نیاز به اجرا دارد یا نه. در زمانی که چنین نیازی باشد، هر فراخوانی تابعی را که می‌یابد به پشته فراخوانی اضافه می‌کند تا به ترتیب اجرا شوند. همه شما «رد پشته خطا» (Error Stack Trace) را می‌شناسید و آن را در دیباگر یا در کنسول مرورگر دیده‌اید.

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

توضیح ساده حلقه Event

به مثال زیر توجه کنید:

const bar = () => console.log('bar')
const baz = () => console.log('baz')
const foo = () => { console.log('foo') bar() baz()}
foo()

//----------
Foobarbaz

 

که مطابق انتظار است. زمانی که این کد اجرا می‌شود ابتدا ()foo فراخوانی می‌شود. درون ()foo ابتدا ()bar را فراخوانی می‌کنیم و سپس ()baz فراخوانی می‌شود. در این مرحله پشته فراخوانی مانند زیر است:

 

حلقه Event در هر تکرار بررسی می‌کند که آیا چیزی در پشته فراخوانی وجود دارد یا نه و آن را اجرا می‌کند:

تا این که پشته فراخوانی خالی شود.

صف‌بندی اجرای تابع

مثال فوق معمولی به نظر می‌رسد و نکته خاصی ندارد: جاوا اسکریپت مواردی که باید اجرا شوند را می‌یابد و آن‌ها را به ترتیب اجرا می‌کند. در ادامه با روش به تعویض انداختن (defer) یک تابع تا زمان خالی شدن پشته آشنا می‌شویم. کاربرد دستور زیر برای فراخوانی یک تابع است:

setTimeout(() => {})، 0)

اما هر بار که تابع دیگری در کد اجرا شود، این دستور نیز اجرا خواهد شد. مثال زیر را در نظر بگیرید:

const bar = () => console.log('bar')
const baz = () => console.log('baz')
const foo = () => { console.log('foo') setTimeout(bar، 0) baz()}
foo()

شاید شگفت‌زده شوید که کد فوق عبارت زیر را در خروجی نمایش می‌دهد:

Foobazbar

زمانی که این کد اجرا شود، ابتدا ()foo فراخوانی می‌شود. درون ()foo ابتدا setTimeout فراخوانی می‌شود و bar به عنوان یک آرگومان ارسال می‌شود. ما آن را طوری تنظیم می‌کنیم تا حد امکان به سرعت اجرا شود و مقدار 0 به عنوان تایمر ارسال می‌شود سپس ()baz را فراخوانی می‌کنیم. در این نقطه پشته فراخوانی مانند زیر خواهد بود:

ترتیب اجرای تابع‌ها

در ادامه ترتیب اجرای همه تابع‌ها را در برنامه مشاهده می‌کنید:

صف پیام

زمانی که ()setTimeout فراخوانی می‌شود، مرورگر یا Node.js تایمر را آغاز می‌کند. زمانی که تایمر منقضی شود، در این حالت از آنجا که مقدار 0 به عنوان timeout تعیین شده است، تابع callback در «صف پیام» (Message Queue) قرار می‌گیرد.

صف پیام جایی است که رویدادهای آغاز شده از سمت کاربر مانند رویدادهای کلیک و ضربه‌های کیبورد و یا واکشی پاسخ‌ها از صف پیش از آن که کد فرصت واکنش به آن‌ها را داشته باشد صف‌بندی می‌شوند. رویدادهای DOM مانند onLoad نیز چنین خصوصیتی دارند.

این حلقه به پشته فراخوانی اولویت می‌دهد. این حلقه ابتدا همه چیز که در پشته فراخوانی بیاید پردازش می‌کند و زمانی که چیزی باقی نماند، اقدام به انتخاب موارد موجود در صف پیام می‌کند.

بدین ترتیب لازم نیست برای تابع‌هایی مانند setTimeout منتظر بمانیم یا این که صبر کنیم واکشی یا دیگر امور به پایان برسند، زیرا از سوی مرورگر ارائه شده‌اند و روی نخ‌های خود زنده هستند. برای نمونه اگر مقدار timeout را با استفاده از دستور setTimeout روی 2 ثانیه تنظیم کرده باشید، لازم نیست 2 ثانیه منتظر بمانید چون انتظار در هر جایی رخ می‌دهد.

صف کار در ES6

استاندارد ECMAScript 2015 مفهوم «صف کار» (Job Queue) را معرفی کرده است که از سوی Pomise-ها مورد استفاده قرار می‌گیرد و روشی برای اجرای نتیجه یک تابع async به محض امکان است و دیگر آن را در انتهای پشته فراخوانی قرار نمی‌دهیم. بدین ترتیب Promise-هایی که پیش از اتمام تابع جاری خاتمه یابند، درست پس از تابع جاری اجرا خواهند شد.

برای مقایسه می‌توانید یک قطار هوایی شهر بازی را در نظر بگیرید. صف پیام شما را در پشت همه افرادی که قبل از شما در صف جای گرفته‌اند قرار می‌دهد، در حالی که صف کار یک بلیت سریع‌السیر است که اجازه می‌دهد درست پس از اتمام یک دور، مجدداً بی‌درنگ سوار قطار هوایی شوید.

مثال:

const bar = () => console.log('bar')
const baz = () => console.log('baz')
const foo = () => { console.log('foo') setTimeout(bar، 0) new Promise((resolve، reject) => resolve('should be right after baz، before bar')).then(resolve => console.log(resolve)) baz()}
foo()

کد فوق عبارت زیر را نمایش می‌دهد:

foobazshould be right after foo، before barbar

این تفاوت بزرگی است که بین Promise-ها (و البته async/await که بر مبنای Promise ساخته شده) با تابع‌های ساده قدیمی ناهمگام که از طریق ()setTimeout یا دیگر API-های پلتفرم اجرا می‌شدند وجود دارد.

درک ()process.nextTick

زمانی که تلاش می‌کنید حلقه رویداد Node.js را درک کنید، یک بخش مهم آن ()process.nextTick است. این بخش با حلقه رویداد به روشی خاص تعامل پیدا می‌کند. هر بار که حلقه رویداد یک دور کامل می‌زند آن را یک tick می‌نامیم.

زمانی که یک تابع را به ()process.nextTick ارسال می‌کنیم به موتور مرورگر دستور می‌دهیم که تابع را در انتهای عملیات جاری و پیش از آغاز تیک بعدی حلقه رویداد احضار کند:

process.nextTick(() => {//do something})

حلقه رویداد مشغول پردازش کردن کد تابع جاری است. زمانی که این عملیات پایان گیرد، موتور جاوا اسکریپت همه تابع‌های ارسالی در فراخوانی‌های nextTick که در طی اجرای این عملیات ارسال شده‌اند را اجرا می‌کند. به این ترتیب به موتور جاوا اسکریپت اعلام می‌کنیم که یک تابع را به روشی ناهمگام (پس از اجرای تابع جاری) اما به سرعت و بدون صف‌بندی پردازش کند. فراخوانی کردن (setTimeout(() => {}، 0 موجب می‌شود که تابع در تیک بعدی و بسیار بعدتر از زمانی که از ()nextTick استفاده می‌کنیم اجرا شود. از ()nextTick زمانی استفاده کنید که می‌خواهید مطمئن شوید در تکرار بعدی حلقه رویداد، کد حتماً اجرا خواهد شد.

درک ()setImmediate

هنگامی که می‌خواهیم بخشی از کد را به صورت ناهمگام اجرا کنیم، اما این کار در سریع‌ترین زمان ممکن صورت گیرد، یک گزینه استفاده از تابع ()setImmediate است که از سوی Node.js ارائه شده است:

setImmediate(() => {//run something})

هر تابعی که به صورت آرگومان ()setImmediate ارسال شود یک callback است که در تکرار بعدی حلقه رویداد اجرا خواهد شد. اینک شاید از خود بپرسید ()setImmediate چه تفاوتی با (setTimeout(() => {}، 0 و یا ()process.nextTick دارد؟ تابعی که به ()process.nextTick ارسال شود در تکرار بعدی حلقه رویداد و پس از پایان یافتن عملیات اجرا خواهد شد. این بدان معنی است که همواره پیش از ()setTimeout و ()setImmediate اجرا می‌شود. یک callback به نام ()setTimeout با تأخیر 0 میلی‌ثانیه بسیار به ()setImmediate شباهت دارد. ترتیب اجرا به عوامل مختلفی وابسته خواهد بود، اما هر دوی آن‌ها در تکرار بعدی حلقه رویداد اجرا خواهند شد.

تایمرها

زمانی که کد جاوا اسکریپت می‌نویسیم ممکن است بخواهیم اجرای یک تابع را به تأخیر بیندازیم. به این منظور می‌توان از ()setTimeout و ()setInterval برای زمان‌بندی اجرای تابع در آینده استفاده کرد.

()setTimeout

هنگامی که کد جاوا اسکریپت می‌نویسیم، می‌توانیم با استفاده از دستور ()setTimeout اجرای یک تابع را به تأخیر بیندازیم. می‌توان یک تابع callback تعیین کرد که بعدتر اجرا شود و مقداری برای میزان این تأخیر در اجرا بر مبنای میلی‌ثانیه تعیین کرد:

setTimeout(() => {// runs after 2 seconds}، 2000)
setTimeout(() => {// runs after 50 milliseconds}، 50)

این ساختار یک تابع جدید تعریف می‌کند. شما می‌توانید تابع دیگر را درون آن فراخوانی کنید یا این که نام یک تابع موجود را به آن ارسال و پارامترهای آن را تعیین کنید:

const myFunction = (firstParam، secondParam) => {// do something}
// runs after 2 secondssetTimeout(myFunction، 2000، firstParam، secondParam)

()setTimeout یک شناسه تایمر بازگشت می‌دهد. این شناسه عموماً استفاده‌ای ندارد، اما می‌توانید آن را ذخیره کنید و در صورتی که بخواهید اجرای این تابع زمان‌بندی‌شده را حذف کنید آن را پاک کنید:

const id = setTimeout(() => {// should run after 2 seconds}، 2000)
// I changed my mindclearTimeout(id)

تأخیر صفر

اگر میزان تأخیر را برابر با 0 تعیین کنید، تابع callback در اولین فرصت ممکن، اما پس از اجرای تابع جاری اجرا خواهد شد:

setTimeout(() => { console.log('after ')}، 0)
console.log(' before ')

کد فوق عبارت زیر را نمایش می‌دهد:

before after

این حالت به طور خاص در مواردی که می‌خواهیم از مسدود شدن CPI روی وظایف سنگین جلوگیری کنیم و اجازه دهیم تابع‌های دیگر نیز در زمان اجرای یک محاسبه سنگین اجرا شوند مفید خواهد بود. این کار از طریق صف‌بندی تابع‌ها در یک جدول زمان‌بندی ممکن خواهد بود. برخی مرورگرها (مانند IE و Edge) یک متد ()setImmediate را پیاده‌سازی کرده‌اند که دقیقاً همین کارکرد را انجام می‌دهد، اما استاندارد نیست و روی مرورگرهای دیگر وجود ندارد. اما این تابع که معرفی کردیم در Node.js یک استاندارد محسوب می‌شود.

()setInterval

()setInterval یک تابع مشابه ()setTimeout است و تنها یک تفاوت دارد. به جای اجرا کردن یک‌باره تابع callback این تابع آن را برای همیشه و در بازه‌های زمانی معین شده (بر حسب میلی‌ثانیه) اجرا می‌کند:

setInterval(() => {// runs every 2 seconds}، 2000)

تابع فوق هر 2 ثانیه یک بار اجرا می‌شود، مگر اینکه با استفاده از clearInterval و ارسال شناسه بازه‌ای که در پی اجرای setInterval بازگشت می‌یابد از آن بخواهیم متوقف شود:

const id = setInterval(() => {// runs every 2 seconds}، 2000)
clearInterval(id)

فراخوانی clearInterval درون تابع callback setInterval رویه‌ای رایج است و بدین ترتیب می‌توان در مورد اجرای مجدد یا توقف آن یک تصمیم‌گیری خودکار داشت. برای نمونه کد زیر کار دیگری را اجرا می‌کند، مگر اینکه App.somethingIWait دارای مقدار arrived باشد:

const interval = setInterval(function() { if (App.somethingIWait === 'arrived') { clearInterval(interval)
// otherwise do things }}، 100

setTimeout بازگشتی

setTimeout یک تابع را هر n میلی‌ثانیه یک بار اجرا می‌کند و هیچ ملاحظه‌ای در مورد زمان پایان اجرای تابع ندارد. اگر یک تابع همواره زمان مشابهی را نیاز داشته باشد، این روش مناسب خواهد بود:

اما ممکن است تابع برای نمونه بسته به شرایط شبکه، برای اجرا به زمان متفاوتی نیاز داشته باشد:

و حتی ممکن است این زمان طولانی اجرا با تابع بعدی همپوشانی پیدا کند:

تعیین setTimout بازگشتی

برای جلوگیری از این وضعیت می‌توان یک setTimeout بازگشتی زمان‌بندی کرد تا زمانی که تابع callback به پایان می‌رسد فراخوانی شود:

const myFunction = () => {// do something
setTimeout(myFunction، 1000)}
setTimeout(myFunction()}، 1000)

برای دستیابی به این سناریو:

 

setTimeout و setInterval هر دو در Node.js از طریق ماژول Timers در اختیار ما قرار گرفته‌اند. ()Node.js تابع setImmediate را نیز ارائه کرده است که معادل استفاده از دستور زیر است:

setTimeout(() => {}، 0)ا

 

تاریخ انتشار: چهارشنبه, ۳۱ ارديبهشت ۱۳۹۹، ۱۰:۳۷ ب.ظ نویسنده: محمدیان

به دلیل اینکه با مباحث مهمی روبرو هستیم، سعی کردم یه منبع پیدا کنم و راجع این مباحث یه مرجع کامل تر داشته باشیم. توجه کنید که ترتیب مباحث از ابتدای صفحه تا انتهای صفحه ست. اول callback رو بفمید و سپس promise و در آخر async و await .

جاوا اسکریپت به صورت پیش‌فرض یک زبان برنامه‌نویسی همگام و تک نخی است. این بدان معنی است که کد نمی‌تواند نخ‌های جدیدی ایجاد کرده و به صورت موازی اجرا شود. در این مقاله به بررسی روش‌های مختلف برنامه نویسی ناهمگام در محیط Node.js می‌پردازیم.

ناهمگامی در زبان‌های برنامه‌نویسی

رایانه‌ها اساساً دارای طراحی ناهمگام هستند. منظور از ناهمگامی این است که کارهای مختلف می‌توانند در گردش برنامه اصلی مستقل از هم اتفاق بیفتند. در رایانه‌های امروز هر برنامه‌ای برای مدت زمان معینی اجرا می‌شود و سپس اجرای آن متوقف می‌شود تا برنامه دیگری بتواند به اجرای خود ادامه بدهد. این کار در چنان چرخه سریعی اتفاق می‌افتد که کاربر هرگز متوجه نمی‌شود و ما فکر می‌کنیم رایانه ما می‌تواند به طور همزمان برنامه‌های زیادی را اجرا کند، اما این یک توهم است (البته قضیه در پردازنده‌های چندهسته‌ای متفاوت است).

برنامه‌ها به صورت داخلی از «وقفه» (interrupt) استفاده می‌کنند. وقفه یک سیگنال است که به سمت پردازنده ارسال می‌شود تا توجه سیستم را کسب کند. پرداختن به جزییات این موضوع خارج از موضوع این مقاله است؛ اما باید به خاطر داشته باشید که ناهمگامی در برنامه‌ها امری معمول است و به طور نرمال برنامه‌ها، اجرای خود را متوقف می‌کنند تا زمانی که پردازنده به آن‌ها وقتی اختصاص بدهد. زمانی که یک برنامه منتظر پاسخی از سوی شبکه است، نمی‌تواند پردازنده را معطل خود نگه دارد تا درخواست پایان یابد.

به طور معمول زبان‌های برنامه‌نویسی همگام هستند. برخی از آن‌ها نیز در حد زبان یا کتابخانه‌های جانبی، روش‌هایی برای مدیریت ناهمگامی ارائه می‌کنند. زبان‌های C ،Java ،C# ،PHP ،Go ،Ruby ،Swift و Python همگی به صورت پیش‌فرض همگام هستند. برخی از این زبان‌ها با استفاده از نخ‌ها به صورت ناهمگام عمل می‌کنند و می‌توانند یک پردازش جدید ایجاد کنند.

جاوا اسکریپت

زبان برنامه‌نویسی جاوا اسکریپت نیز به صورت پیشفرض همگام و تک نخی است. این بدان معنی است که کد نمی‌تواند نخ‌های جدید ایجاد کرده و به صورت موازی اجرا شود. در این حالت، خطوط مختلف کد یکی پس از دیگری و به ترتیب اجرا می‌شوند. برای نمونه:

const a = 1const b = 2const c = a * bconsole.log(c)doSomething()

اما می‌دانیم که جاوا اسکریپت درون مرورگر تولد یافته است و وظیفه اصلی آن در ابتدا پاسخ دادن به واکنش‌های کاربر مانند onClick ،onMouseOver ،onChange ،onSubmit و غیره بوده است. چنین فرایندی در یک مدل برنامه‌نویسی همگام چگونه ممکن است؟

پاسخ در محیط برنامه‌نویسی این زبان است. مرورگر روشی برای ارائه یک مجموعه از API-ها دارد که می‌توانند این نوع کارکرد را مدیریت کنند. در سال‌های اخیر Node.js یک محیط غیر مسدودکننده I/O معرفی کرده است که این مفهوم را به دسترسی فایل‌ها، فراخوانی‌های شبکه و موارد مشابه گسترش داده است.

Callback-ها

ما هرگز نمی‌دانیم که یک کاربر چه زمانی روی یک دکمه کلیک خواهد کرد، بنابراین باید یک «دستگیره رویداد» (event handler) برای رویداد کلیک تعریف کنیم.

این دستگیره رویداد تابعی قبول می‌کند که هنگام اتفاق افتادن رویداد فراخوانی می‌شود:

document.getElementById('button').addEventListener('click'، () => {//item clicked})

این همان callback مشهور است. در واقع callback تابع ساده‌ای است که به صورت یک مقدار به تابع دیگر ارسال می‌شوند و تنها زمانی اجرا خواهد شد که رویدادی اتفاق بیفتد. ما این کار را به این دلیل می‌توانیم اجرا کنیم که جاوا اسکریپت تابع‌های درجه نخست دارد که می‌توانند به متغیرها انتساب یافته و به تابع‌های دیگر (که تابع‌های درجه بالا نامیده می‌شوند) ارسال شوند.

رویه معمول این است که کد کلاینت در یک شنونده رویداد load در شیء window قرار می‌گیرد و تابع callback را در زمان آماده شدن صفحه اجرا می‌کند:

	
window.addEventListener('load'، () => {//window loaded //do what you want}

Callback-ها در همه جا استفاده می‌شوند و اختصاص به رویدادهای DOM ندارند. یک مثال عمومی استفاده از تایمر است:

setTimeout(() => {// runs after 2 seconds}، 2000

درخواست‌های XHR نیز یک callback می‌پذیرند. در مثال زیر یک تابع به مشخصه‌ای که در زمان رخداد اتفاق خاص فراخوانی می‌شود، انتساب خواهد یافت:

const xhr = new XMLHttpRequest() xhr.onreadystatechange = () => {
    if (xhr.readyState === 4) {
        xhr.status === 200 ? console.log(xhr.responseText) : console.error('error')
    }
}
xhr.open('GET', 'https://yoursite.com') xhr.send()

مدیریت خطا در Callback-ها

یکی از رایج‌ترین راهبردها برای مدیریت خطا در callback-ها کاری است که Node.js انجام می‌دهد. پارامتر اول در هر تابع callback شیء خطا است که به نام callback-های error-first شناخته می‌شوند.

اگر خطایی وجود نداشته باشد، این شیء null خواهد بود. اگر خطایی رخ داده باشد این پارامتر نوعی توضیح در مورد خطا و اطلاعات مرتبط ارائه می‌کند.

fs.readFile('/file.json'، (err، data) => { if (err!== null) {//handle error console.log(err) return }

مشکل Callback-ها

به جای استفاده از کال بک میتوانیم کد خود را با پرامیس بنویسیم و یا کدهایی که به صورت کال بک نوشته شده تبدیل به پرامیس کنیم تا بتوانیم در آینده از مزایای async/await هم استفاده کنیم

Callback-ها در استفاده‌های ساده بسیار عالی هستند. اما هر Callback یک سطح به سلسله‌مراتب تودرتو اضافه می‌کند. زمانی که Callback-های زیادی وجود داشته باشند، کد به سرعت پیچیده می‌شود:

window.addEventListener('load'،() => {
    document.getElementById('button').addEventListener('click'،() => {
        setTimeout(() => {
                items.forEach(item => { //your code here
                })
            }،
            2000)
    })
})

این کد صرفاً 4 سطح ساده دارد، اما در موارد زیادی سطوح بسیار بیشتری از کد تودرتو را مشاهده می‌کنیم که جالب نیست. برای حل این مشکل چه باید کرد:

جایگزین‌های Callback-ها

از ES6 به بعد جاوا اسکریپت چند قابلیت معرفی کرده است که به کدنویسی ناهمگام بدون استفاده از Callback-ها کمک می‌کند:

  • Promises (ES6)
  • Async/Await (ES8)

Promise-ها

Promise-ها یک روش برای اجرای کد ناهمگام در جاوا اسکریپت محسوب می‌شوند و با استفاده از آن‌ها دیگر لازم نیست نگران وجود Callback-های زیاد در کد باشیم.

مقدمه‌ای بر Promise-ها

یک Promise عموماً به صورت واسطی برای یک مقدار تعریف می‌شود که در زمانی در آینده موجود خواهد شد. با این که سال‌هاست Promise-ها معرفی شده‌اند اما صرفاً در ES2015 استاندارد و معرفی شدند و هم اکنون در ES2017 با معرفی تابع‌های async منسوخ گشته‌اند. تابع‌های async از API مربوط به Promise ها به عنوان بلوک‌های سازنده خود استفاده می‌کند و از این رو درک آن‌ها حتی در صورتی که بخواهید در کد خود از تابع‌های async به جای promise استفاده کنید ضروری خواهد بود.

طرز کار Promise-ها به طور خلاصه

زمانی که یک Promise فراخوانی می‌شود در «حالت انتظار» (pending state) کار خود را آغاز می‌کند. این بدان معنی است که تابع فراخواننده به اجرای خود ادامه می‌دهد در حالی که منتظر Promise است تا پردازش‌های خودش را اجرا کند و بازخوردی به تابع فراخواننده بدهد.

در این زمان تابع فراخواننده منتظر آن می‌ماند تا Promise را در «حالت حل شده» (resolved state) یا در «حالت رد شده» (rejected state) بازگشت دهد، اما چنان که می‌دانید جاوا اسکریپت همگام است و از این رو در زمانی که Promise کار نمی‌کند، تابع همچنان به اجرای خود ادامه می‌دهد.

کدام API جاوا اسکریپت از Promise-ها استفاده می‌کند؟

علاوه بر کد کاربر و کد کتابخانه‌های مختلف، Promise-ها از سوی API-های مدرن استاندارد وب مانند لیست زیر نیز مورد استفاده قرار می‌گیرند:

  • Battery API
  • Fetch API
  • Service Workers

این که در جاوا اسکریپت مدرن از Promise-ها استفاده نکنید امر بسیار نامحتملی است، بنابراین در ادامه به بررسی دقیق‌تر آن‌ها می‌پردازیم.

ایجاد یک Promise

API مربوط به Promise یک سازنده Promise عرضه می‌کند که با استفاده از ()new Promise مقداردهی اولیه می‌شود:

let done = true
----------------------------------------
const isItDoneYet = new Promise((resolve، reject) => {
    if (done) {
        const workDone = 'Here is the thing I built'
        resolve(workDone)
    } else {
        const why = 'Still working on something else'
        reject(why)
    }
})

چنان که می‌بینید Promise ثابت سراسری done را بررسی می‌کند و اگر درست باشد، یک Promise حل شده و در غیر این صورت Promise رد شده بازگشت می‌یابد. ما با استفاده از resolve و reject می‌توانیم یک مقدار را بازگشت دهیم. در حالت فوق ما صرفاً یک رشته بازگشت می‌دهیم اما می‌توان یک شیء را نیز بازگشت داد.

مصرف کردن یک Promise

در بخش قبلی، با روش ایجاد شدن یک Promise آشنا شدیم. اکنون به بررسی شیوه مصرف یا استفاده شدن یک Promise می‌پردازیم:

const isItDoneYet = new Promise(//...)
-----------------------------------------------------------------
const checkIfItsDone = () => {
    isItDoneYet.then((ok) => {
        console.log(ok)
    }).catch((err) => {
        console.error(err)
    })
}

 

جاوا اسکریپت به صورت پیش‌فرض یک زبان برنامه‌نویسی همگام و تک نخی است. این بدان معنی است که کد نمی‌تواند نخ‌های جدیدی ایجاد کرده و به صورت موازی اجرا شود. در این مقاله به بررسی روش‌های مختلف برنامه نویسی ناهمگام در محیط Node.js می‌پردازیم.

ناهمگامی در زبان‌های برنامه‌نویسی

رایانه‌ها اساساً دارای طراحی ناهمگام هستند. منظور از ناهمگامی این است که کارهای مختلف می‌توانند در گردش برنامه اصلی مستقل از هم اتفاق بیفتند. در رایانه‌های امروز هر برنامه‌ای برای مدت زمان معینی اجرا می‌شود و سپس اجرای آن متوقف می‌شود تا برنامه دیگری بتواند به اجرای خود ادامه بدهد. این کار در چنان چرخه سریعی اتفاق می‌افتد که کاربر هرگز متوجه نمی‌شود و ما فکر می‌کنیم رایانه ما می‌تواند به طور همزمان برنامه‌های زیادی را اجرا کند، اما این یک توهم است (البته قضیه در پردازنده‌های چندهسته‌ای متفاوت است).

برنامه‌ها به صورت داخلی از «وقفه» (interrupt) استفاده می‌کنند. وقفه یک سیگنال است که به سمت پردازنده ارسال می‌شود تا توجه سیستم را کسب کند. پرداختن به جزییات این موضوع خارج از موضوع این مقاله است؛ اما باید به خاطر داشته باشید که ناهمگامی در برنامه‌ها امری معمول است و به طور نرمال برنامه‌ها، اجرای خود را متوقف می‌کنند تا زمانی که پردازنده به آن‌ها وقتی اختصاص بدهد. زمانی که یک برنامه منتظر پاسخی از سوی شبکه است، نمی‌تواند پردازنده را معطل خود نگه دارد تا درخواست پایان یابد.

به طور معمول زبان‌های برنامه‌نویسی همگام هستند. برخی از آن‌ها نیز در حد زبان یا کتابخانه‌های جانبی، روش‌هایی برای مدیریت ناهمگامی ارائه می‌کنند. زبان‌های C ،Java ،C# ،PHP ،Go ،Ruby ،Swift و Python همگی به صورت پیش‌فرض همگام هستند. برخی از این زبان‌ها با استفاده از نخ‌ها به صورت ناهمگام عمل می‌کنند و می‌توانند یک پردازش جدید ایجاد کنند.

جاوا اسکریپت

زبان برنامه‌نویسی جاوا اسکریپت نیز به صورت پیشفرض همگام و تک نخی است. این بدان معنی است که کد نمی‌تواند نخ‌های جدید ایجاد کرده و به صورت موازی اجرا شود. در این حالت، خطوط مختلف کد یکی پس از دیگری و به ترتیب اجرا می‌شوند. برای نمونه:

const a = 1const b = 2const c = a * bconsole.log(c)doSomething()

اما می‌دانیم که جاوا اسکریپت درون مرورگر تولد یافته است و وظیفه اصلی آن در ابتدا پاسخ دادن به واکنش‌های کاربر مانند onClick ،onMouseOver ،onChange ،onSubmit و غیره بوده است. چنین فرایندی در یک مدل برنامه‌نویسی همگام چگونه ممکن است؟

پاسخ در محیط برنامه‌نویسی این زبان است. مرورگر روشی برای ارائه یک مجموعه از API-ها دارد که می‌توانند این نوع کارکرد را مدیریت کنند. در سال‌های اخیر Node.js یک محیط غیر مسدودکننده I/O معرفی کرده است که این مفهوم را به دسترسی فایل‌ها، فراخوانی‌های شبکه و موارد مشابه گسترش داده است.

Callback-ها

ما هرگز نمی‌دانیم که یک کاربر چه زمانی روی یک دکمه کلیک خواهد کرد، بنابراین باید یک «دستگیره رویداد» (event handler) برای رویداد کلیک تعریف کنیم.

این دستگیره رویداد تابعی قبول می‌کند که هنگام اتفاق افتادن رویداد فراخوانی می‌شود:

document.getElementById('button').addEventListener('click'، () => {//item clicked})

این همان callback مشهور است. در واقع callback تابع ساده‌ای است که به صورت یک مقدار به تابع دیگر ارسال می‌شوند و تنها زمانی اجرا خواهد شد که رویدادی اتفاق بیفتد. ما این کار را به این دلیل می‌توانیم اجرا کنیم که جاوا اسکریپت تابع‌های درجه نخست دارد که می‌توانند به متغیرها انتساب یافته و به تابع‌های دیگر (که تابع‌های درجه بالا نامیده می‌شوند) ارسال شوند.

رویه معمول این است که کد کلاینت در یک شنونده رویداد load در شیء window قرار می‌گیرد و تابع callback را در زمان آماده شدن صفحه اجرا می‌کند:

	
window.addEventListener('load'، () => {//window loaded //do what you want}

Callback-ها در همه جا استفاده می‌شوند و اختصاص به رویدادهای DOM ندارند. یک مثال عمومی استفاده از تایمر است:

setTimeout(() => {// runs after 2 seconds}، 2000

درخواست‌های XHR نیز یک callback می‌پذیرند. در مثال زیر یک تابع به مشخصه‌ای که در زمان رخداد اتفاق خاص فراخوانی می‌شود، انتساب خواهد یافت:

const xhr = new XMLHttpRequest() xhr.onreadystatechange = () => {
    if (xhr.readyState === 4) {
        xhr.status === 200 ? console.log(xhr.responseText) : console.error('error')
    }
}
xhr.open('GET', 'https://yoursite.com') xhr.send()

مدیریت خطا در Callback-ها

یکی از رایج‌ترین راهبردها برای مدیریت خطا در callback-ها کاری است که Node.js انجام می‌دهد. پارامتر اول در هر تابع callback شیء خطا است که به نام callback-های error-first شناخته می‌شوند.

اگر خطایی وجود نداشته باشد، این شیء null خواهد بود. اگر خطایی رخ داده باشد این پارامتر نوعی توضیح در مورد خطا و اطلاعات مرتبط ارائه می‌کند.

fs.readFile('/file.json'، (err، data) => { if (err!== null) {//handle error console.log(err) return }

مشکل Callback-ها

Callback-ها در استفاده‌های ساده بسیار عالی هستند. اما هر Callback یک سطح به سلسله‌مراتب تودرتو اضافه می‌کند. زمانی که Callback-های زیادی وجود داشته باشند، کد به سرعت پیچیده می‌شود:

window.addEventListener('load'،() => {
    document.getElementById('button').addEventListener('click'،() => {
        setTimeout(() => {
                items.forEach(item => { //your code here
                })
            }،
            2000)
    })
})

این کد صرفاً 4 سطح ساده دارد، اما در موارد زیادی سطوح بسیار بیشتری از کد تودرتو را مشاهده می‌کنیم که جالب نیست. برای حل این مشکل چه باید کرد؟

جایگزین‌های Callback-ها

از ES6 به بعد جاوا اسکریپت چند قابلیت معرفی کرده است که به کدنویسی ناهمگام بدون استفاده از Callback-ها کمک می‌کند:

  • Promises (ES6)
  • Async/Await (ES8)

Promise-ها

Promise-ها یک روش برای اجرای کد ناهمگام در جاوا اسکریپت محسوب می‌شوند و با استفاده از آن‌ها دیگر لازم نیست نگران وجود Callback-های زیاد در کد باشیم.

مقدمه‌ای بر Promise-ها

یک Promise عموماً به صورت واسطی برای یک مقدار تعریف می‌شود که در زمانی در آینده موجود خواهد شد. با این که سال‌هاست Promise-ها معرفی شده‌اند اما صرفاً در ES2015 استاندارد و معرفی شدند و هم اکنون در ES2017 با معرفی تابع‌های async منسوخ گشته‌اند. تابع‌های async از API مربوط به Promise ها به عنوان بلوک‌های سازنده خود استفاده می‌کند و از این رو درک آن‌ها حتی در صورتی که بخواهید در کد خود از تابع‌های async به جای promise استفاده کنید ضروری خواهد بود.

طرز کار Promise-ها به طور خلاصه

زمانی که یک Promise فراخوانی می‌شود در «حالت انتظار» (pending state) کار خود را آغاز می‌کند. این بدان معنی است که تابع فراخواننده به اجرای خود ادامه می‌دهد در حالی که منتظر Promise است تا پردازش‌های خودش را اجرا کند و بازخوردی به تابع فراخواننده بدهد.

در این زمان تابع فراخواننده منتظر آن می‌ماند تا Promise را در «حالت حل شده» (resolved state) یا در «حالت رد شده» (rejected state) بازگشت دهد، اما چنان که می‌دانید جاوا اسکریپت همگام است و از این رو در زمانی که Promise کار نمی‌کند، تابع همچنان به اجرای خود ادامه می‌دهد.

کدام API جاوا اسکریپت از Promise-ها استفاده می‌کند؟

علاوه بر کد کاربر و کد کتابخانه‌های مختلف، Promise-ها از سوی API-های مدرن استاندارد وب مانند لیست زیر نیز مورد استفاده قرار می‌گیرند:

  • Battery API
  • Fetch API
  • Service Workers

این که در جاوا اسکریپت مدرن از Promise-ها استفاده نکنید امر بسیار نامحتملی است، بنابراین در ادامه به بررسی دقیق‌تر آن‌ها می‌پردازیم.

ایجاد یک Promise

API مربوط به Promise یک سازنده Promise عرضه می‌کند که با استفاده از ()new Promise مقداردهی اولیه می‌شود:

let done = true
----------------------------------------
const isItDoneYet = new Promise((resolve، reject) => {
    if (done) {
        const workDone = 'Here is the thing I built'
        resolve(workDone)
    } else {
        const why = 'Still working on something else'
        reject(why)
    }
})

چنان که می‌بینید Promise ثابت سراسری done را بررسی می‌کند و اگر درست باشد، یک Promise حل شده و در غیر این صورت Promise رد شده بازگشت می‌یابد. ما با استفاده از resolve و reject می‌توانیم یک مقدار را بازگشت دهیم. در حالت فوق ما صرفاً یک رشته بازگشت می‌دهیم اما می‌توان یک شیء را نیز بازگشت داد.

مصرف کردن یک Promise

در بخش قبلی، با روش ایجاد شدن یک Promise آشنا شدیم. اکنون به بررسی شیوه مصرف یا استفاده شدن یک Promise می‌پردازیم:

const isItDoneYet = new Promise(//...)
-----------------------------------------------------------------
const checkIfItsDone = () => {
    isItDoneYet.then((ok) => {
        console.log(ok)
    }).catch((err) => {
        console.error(err)
    })
}

اجرای ()checkIfItsDone موجب اجرا شدن یک Promise به نام ()isItDoneYet می‌شود که منتظر حل شدن با استفاده از Callback-ی به نام then باقی می‌ماند و اگر خطایی رخ دهد آن را در callback با نام catch مدیریت می‌کند.

زنجیره‌سازی Promise-ها

هر Promise می‌تواند به Promise دیگری بازگشت یابد و یک زنجیره از Promise-ها تشکیل دهد. مثالی عالی از زنجیره‌سازی Promise-ها در API با نام Fetch مشاهده می‌شود که یک لایه فوقانی روی API مربوط به XMLHttpRequest است و می‌توان از آن برای ایجاد یک منبع و صف‌بندی یک زنجیره از Promise-ها برای اجرا در زمان واکشی شدن منبع استفاده کرد.

API با نام Fetch یک سازوکار مبتنی بر Promise است به طوری که فراخوانی ()fetch معادل تعریف کردن یک Promise با استفاده از ()new Promise است.

نمونه‌ای از زنجیره‌سازی Promise-ها

const status = (response) => {
    if (response.status >= 200 && response.status < 300) {
        return Promise.resolve(response)
    }
    return Promise.reject(new Error(response.statusText))
}
const json = (response) => response.json()
fetch('/todos.json').then(status).then(json).then((data) => {
    console.log('Request succeeded with JSON response'،
        data)
}).catch((error) => {
    console.log('Request failed'،
        error)
})

در این مثال، ()fetch را فراخوانی می‌کنیم تا فهرستی از آیتم‌های TODO را از فایل todos.json که در ریشه دامنه قرار دارد به دست آوریم و بنابراین یک زنجیره از Promise-ها ایجاد کرده‌ایم.

اجرای ()fetch موجب بازگشت یک response می‌شود که مشخصه‌های زیادی دارد، اما دو مورد از آن‌ها برای ما مهم هستند:

  • Status – یک مقدار عددی است که کد وضعیت HTTP را نشان می‌دهد.
  • statusText – یک پیام وضعیت است که در صورت موفق بودن درخواست، مقدار آن OK خواهد بود.

response یک متد ()json نیز دارد که یک Promise بازگشت می‌دهد و در آن به بررسی محتوای متنی پردازش شده و تبدیل آن به JSON می‌پردازد. با توجه به Promise-های فوق روند رویدادها به این صورت است که Promise اول در زنجیره، تابعی است که ما تعریف کرده‌ایم و آن را ()status می‌نامیم. این Promise وضعیت پاسخ را بررسی می‌کند و در صورتی که پاسخ موفق (کد بین 200 تا 299) نباشد، Promise را رد می‌کند.

این عملیات موجب می‌شود که زنجیره Promise همه Promise-های بعدی لیست شده را رد کند و مستقیماً به گزاره ()catch در انتهای کد برسد و متن Request failed را به همراه پیام خطا لاگ کند. اما اگر Promise اول موفق باشد، تابع ()json را که تعریف کرده‌ایم، فراخوانی می‌کند. از آنجا که Promise قبلی در صورت موفقیت، شیء response را بازگشت داده است، می‌توانیم آن را به عنوان ورودی به Promise دوم بدهیم.

در این حالت، داده‌های JSON پردازش شده را بازگشت می‌دهیم تا Promise سوم مستقیماً JSON را دریافت کند:

.then((data) => { console.log('Request succeeded with JSON response'، data)})

در نهایت آن را در کنسول لاگ می‌کنیم.

مدیریت خطاها

در مثال بخش قبلی، یک catch داشتیم که به زنجیره Promise-ها الصاق می‌شد. هر زمان که جزئی از زنجیره Promise-ها ناموفق باشد و خطایی رخ دهد یا یک Promise رد شود، کنترل به گزاره ()catch در انتهای زنجیره می‌رسد.

new Promise((resolve، reject) => {
    throw new Error('Error')
}).catch((err) => {
    console.error(err)
})

یا

new Promise((resolve، reject) => {
    reject('Error')
}).catch((err) => {
    console.error(err)
})

آبشار سازی خطاها

اگر درون ()catch خطایی رخ دهد، می‌توان یک ()catch دیگر برای مدیریت آن الصاق کرد و این روند همین طور تا انتها ادامه می‌یابد:

new Promise((resolve، reject) => {
    throw new Error('Error')
}).catch((err) => {
    throw new Error('Error')
}).catch((err) => {
    console.error(err)
})

هماهنگ‌سازی Promise-ها

در این بخش به روش هماهنگ کردن چند Promise می‌پردازیم.

()Promise.all

اگر لازم است که Promise-های مختلف را با یکدیگر هماهنگ کنید، می‌توانید از متد ()Promise.all برای تعریف کردن لیستی از Promise-ها استفاده کنید و زمانی که همه آن‌ها حل شدند، تابع دیگری را اجرا کنید.

مثالی از آن به صورت زیر است:

const f1 = fetch('/something.json') 
const f2 = fetch('/something2.json')

Promise.all([f1، f2]).then((res) => {
    console.log('Array of results'،
        res)
}).catch((err) => {
    console.error(err)
})

ساختار destructuring assignment در ES2015 نیز اجازه اجرای چنین کاری را می‌دهد:

Promise.all([f1، f2]).then(([res1، res2]) => {
    console.log('Results'،
        res1، res2)
})

البته شما محدود به استفاده از fetch نیستید و می‌توانید از هر Promise دیگری نیز استفاده کنید.

()Promise.race

این متد زمانی اجرا می‌شود که اولین Promise که به آن ارسال کرده‌اید حل شود و callback الصاق شده به آن را یک بار به همراه نتیجه نخستین Promise حل شده اجرا می‌کند. مثالی از آن به صورت زیر است:

const first = new Promise((resolve، reject) => {
    setTimeout(resolve، 500، 'first')
}) const second = new Promise((resolve، reject) => {
    setTimeout(resolve، 100، 'second')
})

Promise.race([first، second]).then((result) => {
            console.log(result) // second}

یک خطای رایج

اگر با خطای زیر در کنسول مواجه شدید:

Uncaught TypeError: undefined is not a promise

ابتدا باید اطمینان حاصل کنید که به جای ()Promise از ()new Promise استفاده کرده‌اید.

Async و Await

جدیدترین رویکرد به تابع‌های ناهمگام در جاوا اسکریپت Async و Await است. جاوا اسکریپت در طی مدت بسیار کوتاهی (ES2015) استفاده از Callback را کنار گذاشت و به بهره‌گیری از Promise-ها روی آورد. از نسخه ES2017 نیز کدهای ناهمگام در جاوا اسکریپت با استفاده از ساختار async/await ساده‌تر شده‌اند.

تابع‌های async ترکیبی از Promise-ها و generatos-ها هستند و اساساً لایه بالاتری از تجرید نسبت به Promise محسوب می‌شوند. در اینجا باید یک بار دیگر تکرار کنیم که async/await بر مبنای Promise-ها ساخته شده‌اند.

Async/Await چرا معرفی شد؟

تابع‌های Async/Await باعث کاهش حجم کد مورد نیاز برای نوشتن Promise-ها می‌شوند و محدودیت «عدم قطع زنجیره» Promise-های زنجیره‌سازی را نیز مرتفع می‌سازند. زمانی که Promise-ها در نسخه ES2015 معرفی شدند، هدف از ارائه آن‌ها حل مشکلی در کدنویسی ناهمگام بود و در این کار نیز موفق بودند، اما در طی دو سال که بین عرضه نسخه‌های ES2015 و ES2017 وجود داشت مشخص شد که Promise-ها نمی‌توانند راه‌حل نهایی باشند.

Promise-ها برای حل مشکل مشهور جهنم callback-ها عرضه شدند، اما آن‌ها نیز پیچیدگی خاص خود را داشتند و از نظر کاربران دارای ساختار پیچیده‌ای بودند. Promise-ها با این کارکرد که به ما نشان دادند می‌توان از ساختار مناسب‌تری به این منظور استفاده کرد مفید بودند و لذا اینک زمانی فرا رسیده است که از تابع‌های async استفاده کنیم. تابع‌های async/await موجب می‌شوند کد همگام به نظر برسد، اما اساساً ناهمگام است و در پشت صحنه به روشی غیر مسدودکننده عمل می‌کند.

طرز کار Async/Await چگونه است؟

تابع async یک Promise بازگشت می‌دهد. به مثال زیر توجه کنید:

const doSomethingAsync = () => {
    return new Promise((resolve) => {
        setTimeout(() => resolve('I did something')، 3000)
    })
}

زمانی که بخواهیم این تابع را فراخوانی کنیم یک await آماده می‌کنیم و کد فراخوانی کننده متوقف می‌شود تا این که Promise حل یا رد شود. تنها الزام این است که تابع کلاینت باید به صورت async تعریف شود. به مثال زیر توجه کنید:

const doSomething = async () => {
    console.log(await doSomethingAsync())
}

یک مثال ساده

در مثال ساده زیر از async/await برای اجرای ناهمگام یک تابع استفاده شده است:

const doSomethingAsync = () => {
    return new Promise((resolve) => {
        setTimeout(() => resolve('I did something')، 3000)
    })
}
const doSomething = async () => {
    console.log(await doSomethingAsync())
}
console.log('Before') 
doSomething() 
console.log('After')

کد فوق عبارت زیر را در کنسول مرورگر نمایش می‌دهد:

BeforeAfterI did something //after 3s

Promise کردن همه چیز

الصاق کردن کلیدواژه async به هر تابعی به این معنی است که تابع یک Promise بازگشت خواهد داد. حتی اگر این کار به طور صریح انجام نشده باشد، این کار موجب می‌شود که تابع به صورت درونی یک Promise بازگشت دهد. به همین دلیل است که کد زیر معتبر است:

const aFunction = async () => { return 'test'}
aFunction().then(alert) // This will alert 'test'

این کد نیز مانند کد فوق است:

const aFunction = async () => { return Promise.resolve('test')}
aFunction().then(alert) // This will alert 'test

خواندن این کد کاملاً آسان‌تر است

چنان که در مثال فوق می‌بینیم، کد ما بسیار ساده به نظر می‌رسد. آن را با کدی که از Promise-های ساده استفاده می‌کرد و از زنجیره‌سازی و تابع‌های callback بهره می‌گرفت مقایسه کنید. این یک مثال بسیار ساده است، مزیت اصلی زمانی بروز می‌یابد که کد بسیار پیچیده‌تر باشد. برای نمونه با استفاده از Promise-ها به صورت زیر می‌توان یک منبع JSON را دریافت کرده و آن را تحلیل کرد:

const getFirstUserData = () => {
    return fetch('/users.json')
    get users list.then(response => response.json())
    parse JSON.then(users => users[0])
    pick first user.then(user => fetch(`/users/${user.name}`)) 
    get user data.then(userResponse => response.json()) parse JSON
}

getFirstUserData()

کد زیر همان کارکرد فوق را با استفاده از await/async اجرا می‌کند:

const getFirstUserData = async () => {
    const response = await fetch('/users.json') get users list
    const users = await response.json() parse JSON
    const user = users[0] pick first user
    const userResponse = await fetch(`/users/${user.name}`) get user data
    const userData = await user.json() parse JSON
    return userData
}

getFirstUserData()

سری کردن چند تابع Async

تابع‌های Async را می‌توان بسیار ساده به هم زنجیر کرد و ساختار آن نسبت به Promise-های ساده بسیار خواناتر است:

const promiseToDoSomething = () => {
    return new Promise(resolve => {
        setTimeout(() => resolve('I did something'), 10000)
    })
}

const watchOverSomeoneDoingSomething = async () => {
    const something = await promiseToDoSomething() 
    return something + ' and I watched'
}

const watchOverSomeoneWatchingSomeoneDoingSomething = async () => {
    const something = await watchOverSomeoneDoingSomething()
    return something + ' and I watched as well'
}
watchOverSomeoneWatchingSomeoneDoingSomething().then((res) => { console.log(res)})

کد فوق عبارت زیر را نمایش می‌دهد:

I did something and I watched and I watched as well

دیباگ آسان‌تر

دیباگ کردن Promise-ها دشوار است زیرا دیباگر روی کد ناهمگام نمی‌ایستد. اما async/await کار دیباگ را بسیار آسان‌تر ساخته‌اند، زیرا از نظر کامپایلر آن‌ها کد همگام هستند.

Event Emitter در Node.js

با استفاده از Event Emitter در Node.js می‌توان رویدادهای سفارشی ایجاد کرد. اگر با جاوا اسکریپت در مرورگر کار کرده باشید، می‌دانید که بخش عمده تعامل با کاربر از طریق رویدادهایی مانند کلیک‌های ماوس، فشردن کلیدهای کیبورد، واکنش به حرکت ماوس و غیره مدیریت می‌شود. در سمت بک‌اند، Node.js کلاس EventEmitter را ارائه کرده است که برای مدیریت رویدادها استفاده می‌شود. این کلاس را می‌توان با استفاده از کد زیر مقداردهی کرد:

const eventEmitter = require('events').EventEmitter()

این شیء متدهای on و emit برخی متدهای دیگر را عرضه می‌کند.

  • emit – برای تحریک کردن یک رویداد استفاده می‌شود.
  • on – برای افزودن تابع callback استفاده می‌شود که قرار است هنگام تحریک شدن رویداد اجرا شود.

برای نمونه، یک رویداد start ایجاد می‌کنیم و از آنجا که می‌خواهیم مثال ساده‌ای باشد، واکنش ما به آن لاگ کردن پیامی در کنسول است:

eventEmitter.on('start'، () => { console.log('started')})

زمانی که رویداد را اجرا کنیم:

eventEmitter.emit('start')

تابع دستگیره رویداد تحریک می‌شود و لاگ کنسول ایجاد می‌شود. با استفاده از آرگومان‌های اضافی ()emit می‌توان آرگومان‌هایی به دستگیره رویداد ارسال کرد:

eventEmitter.emit('start')
eventEmitter.emit('start'، 23)

آرگومان‌های چندگانه

eventEmitter.on('start'، (start، end) => { console.log(`started from ${start} to ${end}`)})
eventEmitter.emit('start'، 1، 100)

شیء EventEmitter چند متد دیگر نیز برای تعامل با رویدادها در اختیار ما قرار می‌دهد که از آن جمله‌اند:

  • ()once – یک شنونده یک‌بارمصرف اضافه می‌کند.
  • ()removeListener() / off – یک شنونده رویداد را از رویداد حذف می‌کند.
  • ()removeAllListeners – همه شنونده‌ها را از یک رویداد حذف می‌کند.

 

منبع: وبلاگ فرادرس