في العقدة ، تنبعث العديد من الكائنات الأحداث. على سبيل المثال ، سيقوم خادم TCP بنقل حدث "Connect" كلما طلب العميل اتصالًا ، وعلى سبيل المثال ، كلما تتم قراءة جزء كامل من البيانات ، سيقوم نظام الملفات بنقل حدث "بيانات". وتسمى هذه الكائنات بواعث الحدث في العقدة. يسمح جهاز إرسال الحدث للمبرمجين بالاشتراك في الأحداث ذات الاهتمام وربط وظيفة رد الاتصال بالأحداث ذات الصلة ، بحيث يتم استدعاء وظيفة رد الاتصال كلما تنبعث جهاز إرسال الحدث حدثًا. يشبه وضع النشر/الاشتراك إلى حد كبير وضع واجهة المستخدم الرسومية التقليدية ، مثل البرنامج سيتلقى الإخطارات المقابلة عند النقر فوق الزر. باستخدام هذا النموذج ، يمكن أن تتفاعل برامج الخادم عند حدوث بعض الأحداث ، مثل اتصال العميل ، أو البيانات المتوفرة على المقبس ، أو إغلاق الملف.
يمكنك أيضًا إنشاء جهاز إرسال الحدث الخاص بك. في الواقع ، توفر Node فئة زائفة EventEmitter الخاصة التي يمكن استخدامها كفئة أساسية لإنشاء جهاز إرسال الحدث الخاص بك.
فهم وضع رد الاتصال
لا تستخدم البرمجة غير المتزامنة قيم إرجاع الوظيفة للإشارة إلى نهاية استدعاء الوظيفة ، ولكنها تعتمد نمط تمرير لاحق.
"نمط التماس الاستمرارية" (CPS: نمط التماس الاستمرار) هو نمط برمجة ، ويتم نقل التحكم في العملية بشكل صريح إلى العملية التالية ...
ستقبل وظائف على غرار CPS وظيفة كمعلمة إضافية. يتم استخدام هذه الوظيفة للإشارة بشكل صريح إلى العملية التالية للتحكم في البرنامج. عندما تحسب وظيفة CPS "قيمة الإرجاع" الخاصة بها ، فإنها ستدعو الوظيفة التي تمثل العملية التالية للبرنامج وتأخذ "قيمة الإرجاع" لوظيفة CPS كمعلمة لها.
من ويكيبيديا - http://en.wikipedia.org/wiki/Continuation-Passing_style
في نمط البرمجة هذا ، ستستدعي كل وظيفة وظيفة رد الاتصال بعد التنفيذ ، بحيث يمكن للبرنامج الاستمرار في التشغيل. سوف تفهم لاحقًا أن JavaScript مناسب جدًا لأسلوب البرمجة هذا. فيما يلي مثال على تحميل الملفات في الذاكرة تحت العقدة:
نسخة الكود كما يلي:
var fs = require ('fs') ؛
fs.readfile ('/etc/passwd' ، الدالة (err ، fileContent) {
إذا (خطأ) {
رمي الخطأ
}
console.log ('محتوى الملف' ، fileContent.toString ()) ؛
}) ؛
في هذا المثال ، تقوم بتمرير وظيفة مجهولة الهوية كمعلمة ثانية لـ Fs.ReadFile. في الواقع ، هذا يستخدم برمجة CPS لأنك تسلم العملية اللاحقة لتنفيذ البرنامج إلى وظيفة رد الاتصال.
كما ترون ، فإن المعلمة الأولى لوظيفة رد الاتصال هي كائن خطأ. في حالة حدوث خطأ في البرنامج ، ستكون هذه المعلمة مثيلًا لفئة الخطأ. هذا نمط شائع لبرمجة CPS في العقدة.
فهم وضع جهاز إرسال الحدث
في وضع رد الاتصال القياسي ، يتم تمرير الوظيفة كمعلمة إلى الوظيفة المراد تنفيذها. يعمل هذا الوضع بشكل جيد للغاية في السيناريوهات التي يجب إخطار العميل بعد اكتمال الوظيفة. ومع ذلك ، في حالة حدوث أحداث متعددة أثناء تنفيذ وظيفة أو أحداث عدة مرات ، فإن هذا النمط غير مناسب. على سبيل المثال ، إذا كنت ترغب في الإخطار في كل مرة يتلقى فيها المقبس البيانات المتاحة ، فستجد أن وضع رد الاتصال القياسي ليس مفيدًا جدًا في هذا السيناريو. في هذا الوقت ، يأتي وضع جهاز إرسال الحدث في متناول يدي. يمكنك استخدام مجموعة من الواجهات القياسية لفصل مولد الحدث ومستمع الحدث بوضوح.
عند استخدام وضع مولد الحدث ، يتم إشراك كائنين أو أكثر - أجهزة الإرسال المثيرة للمستمعين أو أكثر من مستمعي الأحداث.
جهاز إرسال الحدث ، كما يوحي الاسم ، هو كائن يمكنه إنشاء الأحداث. مستمع الحدث هو رمز مرتبط بجهاز إرسال الحدث للاستماع لأنواع محددة من الأحداث ، مثل المثال التالي:
نسخة الكود كما يلي:
var req = http.request (خيارات ، وظيفة (استجابة) {
استجابة. ("البيانات" ، الدالة (البيانات) {
console.log ("بعض البيانات من الاستجابة" ، البيانات) ؛
}) ؛
استجابة. ("نهاية" ، وظيفة () {
console.log ("انتهى الاستجابة") ؛
}) ؛
}) ؛
req.end () ؛
يوضح هذا الرمز خطوتين ضروريتين عند إنشاء طلب HTTP للوصول إلى خادم HTTP عن بُعد باستخدام HTTP.Request API (انظر الفصل اللاحق). يتبنى السطر الأول "نمط التماس الاستمرار" (CPS: نمط التماس الاستمرار) ، ويمر بوظيفة مضمنة سيتم استدعاؤها عندما يستجيب HTTP. يستخدم API طلب HTTP CPS هنا لأن البرنامج يحتاج إلى الاستمرار في إجراء العمليات اللاحقة بعد تنفيذ وظيفة http.request.
عند تنفيذ http.request ، سيتم استدعاء وظيفة رد الاتصال المجهول ، ويتم تمرير كائن استجابة HTTP إليه كمعلمة. كائن استجابة HTTP هذا هو جهاز إرسال حدث. وفقًا لمستند العقدة ، يمكن أن تنبعث منها العديد من الأحداث بما في ذلك البيانات والنهاية. سيتم استدعاء وظائف رد الاتصال التي تسجلها في كل مرة يحدث فيها الحدث.
كدرس ، استخدم وضع CPS عندما تحتاج إلى استعادة حقوق التنفيذ بعد اكتمال العملية المطلوبة ، واستخدم وضع جهاز إرسال الحدث عندما يمكن أن تحدث الأحداث عدة مرات.
فهم أنواع الأحداث
الأحداث المنقولة لها نوع يمثلها سلسلة. يحتوي المثال السابق على نوعين من الأحداث: "البيانات" و "النهاية" ، وهما أي سلاسل محددة بواسطة جهاز إرسال الحدث. ومع ذلك ، فمن المؤسس تقليديًا أن أنواع الأحداث تتكون عادةً من كلمات صغيرة لا تحتوي على أحرف فارغة.
لا يمكنك استخدام التعليمات البرمجية لاستنتاج أنواع الأحداث التي يمكن أن ينشئها جهاز إرسال الحدث ، لأن واجهة برمجة تطبيقات جهاز إرسال الحدث لا تحتوي على آلية الاستبطان ، لذلك يجب أن يكون لدى واجهة برمجة التطبيقات التي تستخدمها وثائق للإشارة إلى أنه يمكن أن تنبعث منها هذه الأنواع من الأحداث.
بمجرد حدوث حدث ما ، سيقوم جهاز إرسال الحدث بالاتصال بالمستمع المتعلق بالحدث ويمرر البيانات ذات الصلة إلى المستمع كمعلمة. في المثال السابق http.request ، تقبل وظيفة رد الاتصال "البيانات" كائن بيانات كمعلمة أولى والوحيدة ، في حين أن "end" لا يقبل أي بيانات. يتم أيضًا تعريف هذه المعلمات كجزء من عقد API بشكل ذاتي من قبل مؤلف API. سيتم أيضًا شرح توقيعات المعلمة الخاصة بوظائف رد الاتصال هذه في وثائق API لكل باعث حدث.
على الرغم من أن جهاز إرسال الحدث هو واجهة تخدم جميع أنواع الأحداث ، إلا أن حدث "الخطأ" هو تطبيق خاص في العقدة. ستقوم معظم أجهزة إرسال الأحداث في العقدة بإنشاء حدث "خطأ" عندما يحدث خطأ في البرنامج. إذا لم يستمع البرنامج إلى حدث "الخطأ" لجهاز إرسال الحدث ، فسيشارك جهاز إرسال الحدث ويرمي استثناءًا غير معطل لأعلى عند حدوث الخطأ.
يمكنك تشغيل الكود التالي في Node Perl لاختبار التأثير ، الذي يحاكي جهاز إرسال الحدث الذي يمكنه إنشاء حدثين:
نسخة الكود كما يلي:
var em = new (require ('events'). eventemitter) () ؛
Em.emit ('event1') ؛
em.emit ('خطأ' ، خطأ جديد ('خطأي')) ؛
سترى الإخراج التالي:
نسخة الكود كما يلي:
var em = new (require ('events'). eventemitter) () ؛
غير محدد
> em.emit ('event1') ؛
خطأ شنيع
> em.emit ('خطأ' ، خطأ جديد ('خطأ my')) ؛
خطأ: خطأي
في REPL: 1: 18
في replserver.eval (REPL.JS: 80: 21)
في REPL.JS: 190: 20
في replserver.eval (REPL.JS: 87: 5)
في الواجهة. <Noynymous> (REPL.JS: 182: 12)
في interface.emit (events.js: 67: 17)
في interface._online (readline.js: 162: 10)
في interface._line (readline.js: 426: 8)
في interface._ttywrite (readline.js: 603: 14)
في ReadStream. <Noyelsing> (readline.js: 82: 12)
>
في السطر 2 من الكود ، يتم انبعاث حدث يسمى "event1" ، دون أي تأثير ، ولكن عندما ينبعث حدث "الخطأ" ، يتم إلقاء الخطأ على المكدس. إذا كان البرنامج لا يعمل في بيئة سطر أوامر Perl ، فسيتعطل البرنامج بسبب استثناء غير معطل.
باستخدام واجهة برمجة تطبيقات جهاز إرسال الحدث
أي كائن ينفذ وضع جهاز إرسال الحدث (مثل مقبس TCP ، وطلب HTTP ، وما إلى ذلك) ينفذ مجموعة الطرق التالية:
نسخة الكود كما يلي:
.addlistener و .on - إضافة مستمع حدث لأحداث النوع المحدد
. -once - ربط مستمع حدث لا ينفذ إلا مرة واحدة لحدث النوع المحدد
.RemoveEventListener - حذف مستمع ملزم بالحدث المحدد
.RemoVealLeventListener - حذف جميع المستمعين المرتبطون بالحدث المحدد
دعونا نقدمهم بالتفصيل أدناه.
وظائف رد الاتصال الملزمة باستخدام .addlistener () أو .on ()
من خلال تحديد نوع الحدث ووظيفة رد الاتصال ، يمكنك تسجيل الإجراءات التي يتم تنفيذها عند حدوث الحدث. على سبيل المثال ، إذا كانت هناك كتل بيانات متوفرة عندما يقرأ ملف دفق بيانات ، فسيؤدي ذلك إلى إصدار "بيانات". يوضح الرمز التالي كيفية تمرير وظيفة رد الاتصال للسماح للبرنامج بإخبارك بأن حدث البيانات قد حدث.
نسخة الكود كما يلي:
الوظيفة المستلمة (البيانات) {
console.log ("GOT DATA من ملف قراءة الدفق: ٪ J" ، البيانات) ؛
}
readStream.addListener ("البيانات" ، المستلمة) ؛
يمكنك أيضًا استخدام .on ، وهو مجرد اختصار. addListener. الرمز التالي هو نفسه ما ورد أعلاه:
نسخة الكود كما يلي:
الوظيفة المستلمة (البيانات) {
console.log ("GOT DATA من ملف قراءة الدفق: ٪ J" ، البيانات) ؛
}
readStream.on ("البيانات" ، المستلمة) ؛
في الكود السابق ، يمكنك استخدام وظيفة محددة مسبقًا كوظيفة رد الاتصال ، ويمكنك أيضًا استخدام وظيفة مجهولة الهوية لتبسيط الكود:
نسخة الكود كما يلي:
readstream.on ("البيانات" ، الدالة (البيانات) {
console.log ("GOT DATA من ملف قراءة الدفق: ٪ J" ، البيانات) ؛
}) ؛
كما ذكرنا سابقًا ، يعتمد عدد المعلمات والتوقيعات التي تم تمريرها إلى وظيفة رد الاتصال على كائن جهاز إرسال الأحداث المحدد ونوع الحدث. أنها ليست موحدة. يجوز لحدث "البيانات" تمرير كائن مخزن مؤقت للبيانات ، وحدث "الخطأ" يمرر كائن خطأ ، وحدث "النهاية" لتدفق البيانات لا يمرر أي بيانات إلى مستمع الحدث.
ربط مستمعي الأحداث المتعددين
يتيح وضع جهاز إرسال الأحداث مستمعي الأحداث المتعددين للاستماع لنوع الحدث من نفس جهاز إرسال الحدث ، مثل:
نسخة الكود كما يلي:
لدي بعض البيانات هنا.
لدي بعض البيانات هنا أيضًا.
يعد جهاز إرسال الحدث مسؤولاً عن استدعاء جميع المستمعين المرتبطين بنوع الحدث المحدد بالترتيب الذي يتم فيه تسجيل المستمع ، أي:
1. عند حدوث حدث ما ، قد لا يتم استدعاء مستمع الحدث على الفور ، وقد يكون هناك مستمعين آخرين تم استدعاؤهم قبل ذلك.
2. من غير الطبيعي أن يتم إلقاؤه على المكدس ، والذي قد يكون بسبب وجود خطأ في الكود. عندما يتم إرسال حدث ما ، إذا قام مستمع حدث بإلقاء استثناء عند استدعائه ، فقد لا يتم استدعاء بعض مستمعي الأحداث أبدًا. في هذه الحالة ، يمسك جهاز إرسال الحدث بالاستثناء وقد يتعامل معه أيضًا.
انظر المثال التالي:
نسخة الكود كما يلي:
readstream.on ("البيانات" ، الدالة (البيانات) {
رمي خطأ جديد ("حدث خطأ ما") ؛
}) ؛
readstream.on ("البيانات" ، الدالة (البيانات) {
console.log ("لدي بعض البيانات هنا أيضًا.") ؛
}) ؛
نظرًا لأن المستمع الأول يلقي استثناءً ، فلن يتم استدعاء المستمع الثاني.
استخدم .removelistener () لإزالة مستمع حدث من جهاز إرسال الحدث
إذا لم تعد تهتم بحدث على كائن ما ، فيمكنك إلغاء مستمع الحدث المسجل من خلال تحديد نوع الحدث ووظيفة رد الاتصال ، مثل هذا:
نسخة الكود كما يلي:
الوظيفة المستلمة (البيانات) {
console.log ("GOT DATA من ملف قراءة الدفق: ٪ J" ، البيانات) ؛
}
readStream.on ("البيانات" ، المستلمة) ؛
// ...
readstream.removelistener ("Data" ، requiredata) ؛
في هذا المثال ، يقوم السطر الأخير بإزالة مستمع حدث يمكن استدعاؤه في أي وقت في المستقبل من كائن جهاز إرسال الحدث.
من أجل حذف المستمع ، يجب عليك تسمية وظيفة رد الاتصال ، لأن اسم وظيفة رد الاتصال مطلوب عند إضافة وحذفها.
استخدم .once () لتمكين وظيفة رد الاتصال ليتم تنفيذها مرة واحدة على الأكثر
إذا كنت ترغب في الاستماع لحدث ينفذ مرة واحدة على الأكثر ، أو مهتمًا فقط بالمرة الأولى التي يحدث حدث ، يمكنك استخدام وظيفة .once ():
نسخة الكود كما يلي:
الوظيفة المستلمة (البيانات) {
console.log ("GOT DATA من ملف قراءة الدفق: ٪ J" ، البيانات) ؛
}
readStream.once ("البيانات" ، المستلمة) ؛
في الكود أعلاه ، سيتم استدعاء وظيفة المستلمة مرة واحدة فقط. إذا كان كائن ReadStream ينبعث منه حدث بيانات ، فستتم تشغيل وظيفة رد الاتصال المستلم مرة واحدة فقط.
إنها في الواقع مجرد طريقة مريحة ، لأنه يمكن تنفيذها بكل بساطة ، مثل هذا:
نسخة الكود كما يلي:
var eventemitter = require ("الأحداث"). EventEmitter ؛
eventemitter.prototype.once = function (type ، callback) {
var that = هذا ؛
this.on (type ، وظيفة مستمع () {
that.removelistener (النوع ، المستمع) ؛
callback.apply (هذا ، الحجج) ؛
}) ؛
} ؛
في الكود أعلاه ، يمكنك إعادة تعريف وظيفة EventEmitter.prototype.once ، وكذلك إعادة تعريف الوظيفة مرة واحدة لكل كائن موروثة من EventEmitter. يستخدم الكود ببساطة طريقة .on (). بمجرد استلام الحدث ، استخدم .RemoveEventListener () لإلغاء تسجيل وظيفة رد الاتصال واستدعاء وظيفة رد الاتصال الأصلي.
ملاحظة: يستخدم الكود السابق طريقة Function.Apply () ، والتي تقبل كائنًا ويأخذها كمتغير محتوى ومجموعة من المعلمات. في المثال السابق ، يتم تمرير صفيف المعلمة غير المعدلة بشفافية إلى وظيفة رد الاتصال من خلال جهاز إرسال الحدث.
قم بإزالة جميع مستمعي الأحداث من جهاز إرسال الحدث باستخدام .removealllisteners ()
يمكنك إزالة جميع المستمعين المسجلين إلى نوع الحدث المحدد من جهاز إرسال الحدث على النحو التالي:
نسخة الكود كما يلي:
Emitter.removealllisteners (النوع) ؛
على سبيل المثال ، يمكنك إلغاء المستمع لجميع إشارات مقاطعة العمليات مثل هذا:
نسخة الكود كما يلي:
Process.RemoVealLlisteners ("Sigterm") ؛
ملاحظة: كدرس ، يوصى باستخدام هذه الوظيفة فقط عندما تعرف بالضبط ما يتم حذفه. خلاف ذلك ، يجب أن تسمح لأجزاء أخرى من التطبيق بحذف مجموعة مستمع الحدث ، أو يمكنك أيضًا السماح لأجزاء البرنامج بتولي إزالة المستمع بأنفسهم. ولكن بغض النظر عن ما ، لا تزال هذه الوظيفة مفيدة في بعض السيناريوهات النادرة ، مثل عندما تستعد لإغلاق جهاز إرسال الحدث أو إيقاف العملية بأكملها بطريقة منظمة.
إنشاء جهاز إرسال حدث
أجهزة إرسال الأحداث تجعل واجهات البرمجة أكثر عمومية بطريقة رائعة. في وضع البرمجة الشائع وسهل الفهم ، يتصل العميل مباشرة بالوظائف المختلفة ، بينما في وضع جهاز إرسال الحدث ، يرتبط العميل بأحداث مختلفة ، مما يجعل برنامجك أكثر مرونة. (ملاحظة المترجم: هذه الجملة ليست واثقة للغاية ، وتنشر النص الأصلي: يوفر Emitter الحدث طريقة رائعة لجعل واجهة البرمجة أكثر عامة. عند استخدام نمط فهم مشترك ، يرتبط العملاء بالأحداث بدلاً من استدعاء الوظائف ، وجعل البرنامج أكثر مرونة.)
بالإضافة إلى ذلك ، من خلال استخدام أجهزة إرسال الأحداث ، يمكنك أيضًا الحصول على العديد من الميزات ، مثل ربط المستمعين المتعددين غير ذوي الصلة في نفس الحدث.
ورث من جهاز إرسال حدث العقدة
إذا كنت مهتمًا بوضع باعث حدث Node وتعتزم استخدامه في تطبيقك الخاص ، فيمكنك إنشاء فئة زائفة عن طريق وراثة EventEmitter:
نسخة الكود كما يلي:
util = طلب ('util') ؛
var eventEmitter = require ("الأحداث"). EventEmitter ؛
// هذا هو مُنشئ MyClass:
var myClass = function () {
}
util.inherits (myClass ، eventemitter) ؛
ملاحظة: ينشئ util.inherits سلسلة النموذج الأولي لـ MyClass ، بحيث يمكن لمثيل MyClass استخدام طريقة النموذج الأولي لـ EventEmitter.
حدث إطلاق
من خلال الوراثة من EventEmitter ، يمكن لـ MyClass إطلاق أحداث مثل هذا:
نسخة الكود كما يلي:
myclass.prototype.somemethod = function () {
this.emit ("الحدث المخصص" ، "الوسيطة 1" ، "الوسيطة 2") ؛
} ؛
في الكود أعلاه ، عندما يتم استدعاء طريقة Somemethond بواسطة مثيل MyClass ، سيتم تنبعث حدث يسمى "حدث لطيف". سيؤدي هذا الحدث أيضًا إلى تنبعث من سلسلتين كبيانات: "الوسيطة 1" و "الوسيطة 2" ، والتي سيتم تمريرها كمعلمات إلى مستمع الحدث.
يمكن لعميل مثيل MyClass الاستماع إلى حدث "الحدث المخصص" مثل هذا:
نسخة الكود كما يلي:
var myinstance = new myclass () ؛
myinstance.on ('حدث مخصص' ، وظيفة (str1 ، str2) {
console.log ('حصلت على حدث مخصص مع STR1 ٪ S و Str2 ٪ S! "، Str1 ، Str2) ؛
}) ؛
على سبيل المثال ، يمكنك إنشاء فئة مؤشر تنبعث منها أحداث "Trick" مرة واحدة:
نسخة الكود كما يلي:
var util = require ('Util') ،
EventEmitter = مطلوب ("الأحداث"). EventEmitter ؛
var ticker = function () {
var self = this ؛
setInterval (function () {
self.emit ('tick') ؛
} ، 1000) ؛
} ؛
util.Inherits (ticker ، eventemitter) ؛
يمكن للعملاء الذين يستخدمون فئة Ticker إظهار كيفية استخدام فئة Ticker والاستماع إلى أحداث "Trick".
نسخة الكود كما يلي:
var ticker = new ticker () ؛
Ticker.on ("Tick" ، Function () {
console.log ("tick") ؛
}) ؛
ملخص
وضع جهاز إرسال الحدث هو نمط إعادة إدخال يمكن استخدامه لفصل كائن جهاز إرسال الحدث من مجموعة من التعليمات البرمجية لحدث معين.
يمكنك استخدام event_emitter.on () لتسجيل المستمعين لأنواع محددة من الأحداث و unregister مع event_emitter.removelistener ().
يمكنك أيضًا إنشاء باعث الحدث الخاص بك عن طريق ورث EventEmitter وببساطة استخدام وظيفة .emit ().