Event Bus ونمط Observer في JavaScript (Node.js): التنفيذ والأمثلة

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

Event Bus ونمط Observer في JavaScript (Node.js)

\n\n

في التطوير الحديث باستخدام Node.js، غالبًا ما تنشأ الحاجة إلى تنظيم تفاعل ضعيف الاقتران بين مكونات التطبيق. لحل هذه المشكلة، يعتبر نمط Observer (المراقب) وتنفيذه العملي Event Bus (ناقل الأحداث) مثاليين. في هذه المقالة، سنشرح بالتفصيل ما هو Event Bus، وكيف يرتبط بنمط Observer، وسننشئ تنفيذنا الخاص باستخدام JavaScript الخالص لـ Node.js.

\n\n

ما هو نمط Observer؟

\n\n

يحدد نمط Observer علاقة "واحد إلى متعدد" بين الكائنات. عندما يغير كائن واحد (الموضوع أو الناشر) حالته، يتم إخطار جميع الكائنات التابعة له (المراقبون أو المشتركون) تلقائيًا بذلك. في Node.js، هذا النمط مدمج في النواة من خلال الفئة EventEmitter.

\n\n

المكونات الرئيسية للنمط:

\n
    \n
  • Subject (الموضوع) — الكائن الذي يولد الأحداث.
  • \n
  • Observer (المراقب) — الكائن الذي يشترك في الأحداث.
  • \n
  • Subscription (الاشتراك) — آلية تسجيل المراقب لدى الموضوع.
  • \n
\n\n

ما هو Event Bus؟

\n\n

Event Bus هو وسيط مركزي ينفذ نمط Observer. بدلاً من أن يشترك كل مكون مباشرة في مكون آخر، تتواصل جميع المكونات من خلال ناقل أحداث واحد. وهذا يوفر المزايا التالية:

\n
    \n
  • اقتران ضعيف بين المكونات.
  • \n
  • سهولة إضافة مشتركين جدد دون تغيير كود الناشر.
  • \n
  • إمكانية الإدارة المركزية للأحداث (التسجيل، التصفية، التصحيح).
  • \n
\n\n

EventEmitter المدمج في Node.js

\n\n

توفر Node.js وحدة events المدمجة، والتي تحتوي على الفئة EventEmitter. هذا هو تنفيذ جاهز لـ Event Bus. لنلقِ نظرة على مثال أساسي:

\n\n
const EventEmitter = require('events');\nconst eventBus = new EventEmitter();\n\n// الاشتراك في حدث 'user:login'\neventBus.on('user:login', (user) => {\n    console.log(`المستخدم ${user.name} قام بتسجيل الدخول`);\n});\n\n// الاشتراك بمعالج آخر\neventBus.on('user:login', (user) => {\n    console.log(`نرسل بريدًا ترحيبيًا إلى ${user.email}`);\n});\n\n// توليد الحدث\neventBus.emit('user:login', { name: 'إيفان', email: 'ivan@example.com' });\n// الإخراج:\n// المستخدم إيفان قام بتسجيل الدخول\n// نرسل بريدًا ترحيبيًا إلى ivan@example.com
\n\n

إنشاء Event Bus خاص بك

\n\n

في بعض الأحيان، لا يكون EventEmitter المدمج كافيًا — على سبيل المثال، إذا كنت بحاجة إلى إضافة دعم للمعالجات غير المتزامنة، أو الأولويات، أو الكتابة الصارمة. دعنا ننشئ تنفيذنا الخاص لـ Event Bus من الصفر:

\n\n
class EventBus {\n    constructor() {\n        this.events = {};\n    }\n\n    // الاشتراك في حدث\n    on(eventName, callback) {\n        if (!this.events[eventName]) {\n            this.events[eventName] = [];\n        }\n        this.events[eventName].push(callback);\n        \n        // إرجاع دالة لإلغاء الاشتراك\n        return () => {\n            this.events[eventName] = this.events[eventName]\n                .filter(cb => cb !== callback);\n        };\n    }\n\n    // الاشتراك في حدث لمرة واحدة\n    once(eventName, callback) {\n        const wrapper = (...args) => {\n            callback(...args);\n            this.off(eventName, wrapper);\n        };\n        this.on(eventName, wrapper);\n    }\n\n    // توليد الحدث\n    emit(eventName, ...args) {\n        const callbacks = this.events[eventName];\n        if (!callbacks) return false;\n        \n        callbacks.forEach(callback => {\n            try {\n                callback(...args);\n            } catch (error) {\n                console.error(`خطأ في معالج الحدث ${eventName}:`, error);\n            }\n        });\n        return true;\n                    

توصيات