Skip to content

الأحداث

[مستقر: 2 - مستقر]

مستقر: 2 استقرار: 2 - مستقر

رمز المصدر: lib/events.js

يعتمد الكثير من واجهة برمجة تطبيقات Node.js الأساسية على بنية غير متزامنة مدفوعة بالأحداث، حيث تقوم أنواع معينة من الكائنات (تسمى "الباعثات") بإصدار أحداث مسماة تتسبب في استدعاء كائنات Function ("مستمعون").

على سبيل المثال: يصدر كائن net.Server حدثًا في كل مرة يتصل به نظير؛ ويصدر كائن fs.ReadStream حدثًا عند فتح الملف؛ ويصدر تيار حدثًا كلما توافرت بيانات للقراءة.

جميع الكائنات التي تصدر أحداثًا هي مثيلات من فئة EventEmitter. تعرض هذه الكائنات دالة eventEmitter.on() التي تسمح بإرفاق دالة واحدة أو أكثر بالأحداث المسماة التي يصدرها الكائن. عادةً ما تكون أسماء الأحداث سلاسل نصية مكتوبة بأسلوب الإبل، ولكن يمكن استخدام أي مفتاح خاصية جافا سكريبت صالح.

عندما يصدر كائن EventEmitter حدثًا، يتم استدعاء جميع الدوال المرفقة بهذا الحدث المحدد بشكل متزامن. يتم تجاهل ورمي أي قيم تُرجعها المستمعون المستدعون.

يُظهر المثال التالي مثيلًا بسيطًا لـ EventEmitter مع مستمع واحد. تُستخدم طريقة eventEmitter.on() لتسجيل المستمعين، بينما تُستخدم طريقة eventEmitter.emit() لتحريك الحدث.

js
import { EventEmitter } from 'node:events'

class MyEmitter extends EventEmitter {}

const myEmitter = new MyEmitter()
myEmitter.on('event', () => {
  console.log('حدث ما!')
})
myEmitter.emit('event')
js
const EventEmitter = require('node:events')

class MyEmitter extends EventEmitter {}

const myEmitter = new MyEmitter()
myEmitter.on('event', () => {
  console.log('حدث ما!')
})
myEmitter.emit('event')

تمرير الوسائط و this إلى المستمعين

تسمح طريقة eventEmitter.emit() بتمرير مجموعة عشوائية من الوسائط إلى دوال المستمع. ضع في اعتبارك أنه عندما يتم استدعاء دالة مستمع عادية، يتم تعيين الكلمة الأساسية this القياسية عمدًا للإشارة إلى مثيل EventEmitter الذي تم إرفاق المستمع به.

js
import { EventEmitter } from 'node:events'
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter()
myEmitter.on('event', function (a, b) {
  console.log(a, b, this, this === myEmitter)
  // يطبع:
  //   a b MyEmitter {
  //     _events: [Object: null prototype] { event: [Function (anonymous)] },
  //     _eventsCount: 1,
  //     _maxListeners: undefined,
  //     [Symbol(shapeMode)]: false,
  //     [Symbol(kCapture)]: false
  //   } true
})
myEmitter.emit('event', 'a', 'b')
js
const EventEmitter = require('node:events')
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter()
myEmitter.on('event', function (a, b) {
  console.log(a, b, this, this === myEmitter)
  // يطبع:
  //   a b MyEmitter {
  //     _events: [Object: null prototype] { event: [Function (anonymous)] },
  //     _eventsCount: 1,
  //     _maxListeners: undefined,
  //     [Symbol(shapeMode)]: false,
  //     [Symbol(kCapture)]: false
  //   } true
})
myEmitter.emit('event', 'a', 'b')

من الممكن استخدام دوال السهم ES6 كمستمعين، ومع ذلك، عند القيام بذلك، لن تشير الكلمة الأساسية this إلى مثيل EventEmitter بعد الآن:

js
import { EventEmitter } from 'node:events'
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter()
myEmitter.on('event', (a, b) => {
  console.log(a, b, this)
  // يطبع: a b undefined
})
myEmitter.emit('event', 'a', 'b')
js
const EventEmitter = require('node:events')
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter()
myEmitter.on('event', (a, b) => {
  console.log(a, b, this)
  // يطبع: a b {}
})
myEmitter.emit('event', 'a', 'b')

غير متزامن مقابل متزامن

تستدعي EventEmitter جميع المستمعين بشكل متزامن بالترتيب الذي تم تسجيلهم به. هذا يضمن تسلسل الأحداث الصحيح ويساعد على تجنب حالات السباق والأخطاء المنطقية. عند الاقتضاء، يمكن لوظائف المستمع التبديل إلى وضع التشغيل غير المتزامن باستخدام طريقتي setImmediate() أو process.nextTick():

js
import { EventEmitter } from 'node:events'
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter()
myEmitter.on('event', (a, b) => {
  setImmediate(() => {
    console.log('هذا يحدث بشكل غير متزامن')
  })
})
myEmitter.emit('event', 'a', 'b')
js
const EventEmitter = require('node:events')
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter()
myEmitter.on('event', (a, b) => {
  setImmediate(() => {
    console.log('هذا يحدث بشكل غير متزامن')
  })
})
myEmitter.emit('event', 'a', 'b')

معالجة الأحداث مرة واحدة فقط

عندما يتم تسجيل مستمع باستخدام طريقة eventEmitter.on()، يتم استدعاء هذا المستمع في كل مرة يتم فيها إصدار الحدث المسمى.

js
import { EventEmitter } from 'node:events'
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter()
let m = 0
myEmitter.on('event', () => {
  console.log(++m)
})
myEmitter.emit('event')
// يطبع: 1
myEmitter.emit('event')
// يطبع: 2
js
const EventEmitter = require('node:events')
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter()
let m = 0
myEmitter.on('event', () => {
  console.log(++m)
})
myEmitter.emit('event')
// يطبع: 1
myEmitter.emit('event')
// يطبع: 2

باستخدام طريقة eventEmitter.once()، من الممكن تسجيل مستمع يتم استدعاؤه مرة واحدة على الأكثر لحدث معين. بمجرد إصدار الحدث، يتم إلغاء تسجيل المستمع ثم يتم استدعاؤه.

js
import { EventEmitter } from 'node:events'
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter()
let m = 0
myEmitter.once('event', () => {
  console.log(++m)
})
myEmitter.emit('event')
// يطبع: 1
myEmitter.emit('event')
// تم تجاهله
js
const EventEmitter = require('node:events')
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter()
let m = 0
myEmitter.once('event', () => {
  console.log(++m)
})
myEmitter.emit('event')
// يطبع: 1
myEmitter.emit('event')
// تم تجاهله

أحداث الخطأ

عندما يحدث خطأ داخل مثيل EventEmitter، فإن الإجراء النموذجي هو إصدار حدث 'error' . تُعامل هذه الحالات كحالات خاصة داخل Node.js.

إذا لم يكن لدى EventEmitter مستمع واحد على الأقل مسجل لحدث 'error'، وتم إصدار حدث 'error'، فسيتم إرسال الخطأ، وطباعة تتبع المكدس، وسيخرج عملية Node.js.

js
import { EventEmitter } from 'node:events'
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter()
myEmitter.emit('error', new Error('whoops!'))
// يطرح الخطأ ويؤدي إلى تعطل Node.js
js
const EventEmitter = require('node:events')
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter()
myEmitter.emit('error', new Error('whoops!'))
// يطرح الخطأ ويؤدي إلى تعطل Node.js

لحماية عملية Node.js من التعطل، يمكن استخدام وحدة domain. (لاحظ، مع ذلك، أن وحدة node:domain قد عفا عليها الزمن).

كممارسة أفضل، يجب دائمًا إضافة مستمعين لأحداث 'error' .

js
import { EventEmitter } from 'node:events'
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter()
myEmitter.on('error', err => {
  console.error('whoops! there was an error')
})
myEmitter.emit('error', new Error('whoops!'))
// يطبع: whoops! there was an error
js
const EventEmitter = require('node:events')
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter()
myEmitter.on('error', err => {
  console.error('whoops! there was an error')
})
myEmitter.emit('error', new Error('whoops!'))
// يطبع: whoops! there was an error

من الممكن مراقبة أحداث 'error' دون استهلاك الخطأ الصادر عن طريق تثبيت مستمع باستخدام الرمز events.errorMonitor.

js
import { EventEmitter, errorMonitor } from 'node:events'

const myEmitter = new EventEmitter()
myEmitter.on(errorMonitor, err => {
  MyMonitoringTool.log(err)
})
myEmitter.emit('error', new Error('whoops!'))
// لا يزال يطرح الخطأ ويؤدي إلى تعطل Node.js
js
const { EventEmitter, errorMonitor } = require('node:events')

const myEmitter = new EventEmitter()
myEmitter.on(errorMonitor, err => {
  MyMonitoringTool.log(err)
})
myEmitter.emit('error', new Error('whoops!'))
// لا يزال يطرح الخطأ ويؤدي إلى تعطل Node.js

التقاط رفض الوعود

إن استخدام دوال async مع مُعالجات الأحداث أمرٌ مُشكِل، لأنه قد يؤدي إلى رفضٍ غير مُعالَج في حالة حدوث استثناء مُلقى:

js
import { EventEmitter } from 'node:events'
const ee = new EventEmitter()
ee.on('something', async value => {
  throw new Error('kaboom')
})
js
const EventEmitter = require('node:events')
const ee = new EventEmitter()
ee.on('something', async value => {
  throw new Error('kaboom')
})

يُغيّر خيار captureRejections في مُنشئ EventEmitter أو الإعداد العام هذا السلوك، حيث يُثبت مُعالِج .then(undefined, handler) على Promise. يُوجّه هذا المُعالِج الاستثناء بشكلٍ غير مُزامن إلى طريقة Symbol.for('nodejs.rejection') إذا وُجدت، أو إلى مُعالِج حدث 'error' إذا لم تُوجَد.

js
import { EventEmitter } from 'node:events'
const ee1 = new EventEmitter({ captureRejections: true })
ee1.on('something', async value => {
  throw new Error('kaboom')
})

ee1.on('error', console.log)

const ee2 = new EventEmitter({ captureRejections: true })
ee2.on('something', async value => {
  throw new Error('kaboom')
})

ee2[Symbol.for('nodejs.rejection')] = console.log
js
const EventEmitter = require('node:events')
const ee1 = new EventEmitter({ captureRejections: true })
ee1.on('something', async value => {
  throw new Error('kaboom')
})

ee1.on('error', console.log)

const ee2 = new EventEmitter({ captureRejections: true })
ee2.on('something', async value => {
  throw new Error('kaboom')
})

ee2[Symbol.for('nodejs.rejection')] = console.log

سيُغيّر تعيين events.captureRejections = true الإعداد الافتراضي لجميع مثيلات EventEmitter الجديدة.

js
import { EventEmitter } from 'node:events'

EventEmitter.captureRejections = true
const ee1 = new EventEmitter()
ee1.on('something', async value => {
  throw new Error('kaboom')
})

ee1.on('error', console.log)
js
const events = require('node:events')
events.captureRejections = true
const ee1 = new events.EventEmitter()
ee1.on('something', async value => {
  throw new Error('kaboom')
})

ee1.on('error', console.log)

لا تحتوي أحداث 'error' التي تم إنشاؤها بواسطة سلوك captureRejections على مُعالِج استثناء لتجنب حلقات الخطأ اللانهائية: التوصية هي عدم استخدام دوال async كمعالجات أحداث 'error'.

الصنف: EventEmitter

[السجل]

الإصدارالتغييرات
v13.4.0، v12.16.0تمت إضافة خيار captureRejections.
v0.1.26تمت الإضافة في: v0.1.26

يتم تعريف وتصدير مُنشئ الكائنات EventEmitter بواسطة الوحدة النمطية node:events:

js
import { EventEmitter } from 'node:events'
js
const EventEmitter = require('node:events')

يصدر جميع مُنشئو الكائنات EventEmitter الحدث 'newListener' عند إضافة مستمعين جدد و'removeListener' عند إزالة المستمعين الحاليين.

يدعم الخيار التالي:

الحدث: 'newListener'

تمت الإضافة في: v0.1.26

  • eventName <string> | <symbol> اسم الحدث الذي يتم الاستماع إليه
  • listener <Function> دالة مُعالِج الحدث

سيصدر مُنشئ الكائنات EventEmitter حدث 'newListener' الخاص به قبل إضافة مستمع إلى مُصفوفة المستمعين الداخلية الخاصة به.

يتم تمرير اسم الحدث وإشارة إلى المستمع الذي يتم إضافته إلى المستمعين المسجلين لحدث 'newListener'.

تتمثل الحقيقة التي يتم تشغيل الحدث قبل إضافة المستمع في تأثير جانبي دقيق ولكنه مهم: يتم إدراج أي مستمعين إضافيين مسجلين لنفس name ضمن استدعاء الوظيفة المرتجع 'newListener' قبل المستمع الذي يجري إضافته.

js
import { EventEmitter } from 'node:events'
class MyEmitter extends EventEmitter {}

const myEmitter = new MyEmitter()
// لا تفعل هذا إلا مرة واحدة حتى لا تدخل في حلقة لانهائية
myEmitter.once('newListener', (event, listener) => {
  if (event === 'event') {
    // إدراج مستمع جديد في المقدمة
    myEmitter.on('event', () => {
      console.log('B')
    })
  }
})
myEmitter.on('event', () => {
  console.log('A')
})
myEmitter.emit('event')
// يُطبع:
//   B
//   A
js
const EventEmitter = require('node:events')
class MyEmitter extends EventEmitter {}

const myEmitter = new MyEmitter()
// لا تفعل هذا إلا مرة واحدة حتى لا تدخل في حلقة لانهائية
myEmitter.once('newListener', (event, listener) => {
  if (event === 'event') {
    // إدراج مستمع جديد في المقدمة
    myEmitter.on('event', () => {
      console.log('B')
    })
  }
})
myEmitter.on('event', () => {
  console.log('A')
})
myEmitter.emit('event')
// يُطبع:
//   B
//   A

حدث: 'removeListener'

[السجل]

الإصدارالتغييرات
v6.1.0, v4.7.0بالنسبة إلى المستمعين المرفقين باستخدام .once()، فإن وسيطة listener الآن تُنتج دالة المستمع الأصلية.
v0.9.3تمت الإضافة في: v0.9.3

يُصدر حدث 'removeListener' بعد إزالة listener.

emitter.addListener(eventName, listener)

تمت الإضافة في: v0.1.26

اسم آخر لـ emitter.on(eventName, listener).

emitter.emit(eventName[, ...args])

تمت الإضافة في: v0.1.26

تُدعي بشكل متزامن كل مستمع مُسجّل للحدث المسمّى eventName، بالترتيب الذي تم تسجيلهم به، و تمرير الوسائط المُقدّمة إلى كل منها.

ترجع true إذا كان الحدث يحتوي على مستمعين، false بخلاف ذلك.

js
import { EventEmitter } from 'node:events'
const myEmitter = new EventEmitter()

// أول مستمع
myEmitter.on('event', function firstListener() {
  console.log('Helloooo! أول مستمع')
})
// ثاني مستمع
myEmitter.on('event', function secondListener(arg1, arg2) {
  console.log(`حدث مع بارامترات ${arg1}, ${arg2} في ثاني مستمع`)
})
// ثالث مستمع
myEmitter.on('event', function thirdListener(...args) {
  const parameters = args.join(', ')
  console.log(`حدث مع بارامترات ${parameters} في ثالث مستمع`)
})

console.log(myEmitter.listeners('event'))

myEmitter.emit('event', 1, 2, 3, 4, 5)

// يُطبع:
// [
//   [Function: firstListener],
//   [Function: secondListener],
//   [Function: thirdListener]
// ]
// Helloooo! أول مستمع
// حدث مع بارامترات 1, 2 في ثاني مستمع
// حدث مع بارامترات 1, 2, 3, 4, 5 في ثالث مستمع
js
const EventEmitter = require('node:events')
const myEmitter = new EventEmitter()

// أول مستمع
myEmitter.on('event', function firstListener() {
  console.log('Helloooo! أول مستمع')
})
// ثاني مستمع
myEmitter.on('event', function secondListener(arg1, arg2) {
  console.log(`حدث مع بارامترات ${arg1}, ${arg2} في ثاني مستمع`)
})
// ثالث مستمع
myEmitter.on('event', function thirdListener(...args) {
  const parameters = args.join(', ')
  console.log(`حدث مع بارامترات ${parameters} في ثالث مستمع`)
})

console.log(myEmitter.listeners('event'))

myEmitter.emit('event', 1, 2, 3, 4, 5)

// يُطبع:
// [
//   [Function: firstListener],
//   [Function: secondListener],
//   [Function: thirdListener]
// ]
// Helloooo! أول مستمع
// حدث مع بارامترات 1, 2 في ثاني مستمع
// حدث مع بارامترات 1, 2, 3, 4, 5 في ثالث مستمع

emitter.eventNames()

مضاف في: v6.0.0

يُرجع مصفوفة تُدرج الأحداث التي قام المُصدر بتسجيل مُستمعين لها. القيم في المصفوفة هي سلاسل أو رموز Symbol.

js
import { EventEmitter } from 'node:events'

const myEE = new EventEmitter()
myEE.on('foo', () => {})
myEE.on('bar', () => {})

const sym = Symbol('symbol')
myEE.on(sym, () => {})

console.log(myEE.eventNames())
// يُطبع: [ 'foo', 'bar', Symbol(symbol) ]
js
const EventEmitter = require('node:events')

const myEE = new EventEmitter()
myEE.on('foo', () => {})
myEE.on('bar', () => {})

const sym = Symbol('symbol')
myEE.on(sym, () => {})

console.log(myEE.eventNames())
// يُطبع: [ 'foo', 'bar', Symbol(symbol) ]

emitter.getMaxListeners()

مضاف في: v1.0.0

يُرجع القيمة القصوى الحالية للمُستمع لـ EventEmitter والتي إما أن يتم تعيينها بواسطة emitter.setMaxListeners(n) أو أن تكون افتراضية events.defaultMaxListeners.

emitter.listenerCount(eventName[, listener])

[History]

الإصدارالتغييرات
v19.8.0, v18.16.0تمت إضافة وسيطة listener.
v3.2.0مضاف في: v3.2.0

يُرجع عدد المُستمعين الذين يستمعون إلى الحدث المسمى eventName. إذا تم توفير listener، فسوف يُرجع عدد مرات العثور على المُستمع في قائمة مُستمعي الحدث.

emitter.listeners(eventName)

[History]

الإصدارالتغييرات
v7.0.0بالنسبة للقاطعون المرفقون باستخدام .once()، هذا يعيد القواطع الأصلية بدلاً من دوال التغليف الآن.
v0.1.26تمت الإضافة في: v0.1.26

يعيد نسخة من مجموعة القواطع للحدث المسمى eventName.

js
server.on('connection', stream => {
  console.log('someone connected!')
})
console.log(util.inspect(server.listeners('connection')))
// يطبع: [ [Function] ]

emitter.off(eventName, listener)

تمت الإضافة في: v10.0.0

اسم آخر لـ emitter.removeListener().

emitter.on(eventName, listener)

تمت الإضافة في: v0.1.101

يضيف دالة listener إلى نهاية مجموعة القواطع للحدث المسمى eventName. لا يتم إجراء أي فحوصات للتحقق مما إذا تم إضافة listener بالفعل. ستؤدي العديد من المكالمات التي تمرر نفس مجموعة eventName و listener إلى إضافة listener، واستدعائها، عدة مرات.

js
server.on('connection', stream => {
  console.log('someone connected!')
})

يعيد مرجعًا إلى EventEmitter، بحيث يمكن سلسلة المكالمات.

افتراضيًا، يتم استدعاء مستمعي الأحداث بالترتيب الذي تمت إضافتهم به. يمكن استخدام طريقة emitter.prependListener() كبديل لإضافة مستمع الحدث إلى بداية مجموعة القواطع.

js
import { EventEmitter } from 'node:events'
const myEE = new EventEmitter()
myEE.on('foo', () => console.log('a'))
myEE.prependListener('foo', () => console.log('b'))
myEE.emit('foo')
// يطبع:
//   b
//   a
js
const EventEmitter = require('node:events')
const myEE = new EventEmitter()
myEE.on('foo', () => console.log('a'))
myEE.prependListener('foo', () => console.log('b'))
myEE.emit('foo')
// يطبع:
//   b
//   a

emitter.once(eventName, listener)

مضاف في: v0.3.0

يضيف دالة listener للمرة الواحدة لحدث يُسمى eventName. في المرة التالية التي يتم فيها تشغيل eventName، تتم إزالة هذا المُستمع ثم يتم استدعاؤه.

js
server.once('connection', stream => {
  console.log('أها، لدينا أول مستخدم!')
})

يُرجع مرجعًا إلى EventEmitter، بحيث يمكن سلسلة المكالمات.

افتراضيًا، يتم استدعاء مُستمعي الأحداث بالترتيب الذي تمت إضافتهم به. يمكن استخدام طريقة emitter.prependOnceListener() كبديل لإضافة مُستمع الحدث إلى بداية مصفوفة المُستمعين.

js
import { EventEmitter } from 'node:events'
const myEE = new EventEmitter()
myEE.once('foo', () => console.log('a'))
myEE.prependOnceListener('foo', () => console.log('b'))
myEE.emit('foo')
// يُطبع:
//   b
//   a
js
const EventEmitter = require('node:events')
const myEE = new EventEmitter()
myEE.once('foo', () => console.log('a'))
myEE.prependOnceListener('foo', () => console.log('b'))
myEE.emit('foo')
// يُطبع:
//   b
//   a

emitter.prependListener(eventName, listener)

مضاف في: v6.0.0

يضيف دالة listener إلى بداية مصفوفة المُستمعين لحدث يُسمى eventName. لا يتم إجراء أي فحوصات للتحقق مما إذا كان listener قد تمت إضافته بالفعل. ستؤدي العديد من المكالمات التي تمرر نفس مجموعة eventName و listener إلى إضافة listener، واستدعائه، عدة مرات.

js
server.prependListener('connection', stream => {
  console.log('شخص ما اتصل!')
})

يُرجع مرجعًا إلى EventEmitter، بحيث يمكن سلسلة المكالمات.

emitter.prependOnceListener(eventName, listener)

مضاف في: v6.0.0

يضيف دالة مُستمع لمرة واحدة listener للحدث المسمى eventName إلى بداية مُصفوفة المُستمعين. في المرة التالية التي يتم فيها تشغيل eventName، يتم إزالة هذا المُستمع، ثم يتم استدعاؤه.

js
server.prependOnceListener('connection', stream => {
  console.log('Ah, we have our first user!')
})

يرجع مرجعًا إلى EventEmitter، بحيث يمكن سلسلة المكالمات.

emitter.removeAllListeners([eventName])

مضاف في: v0.1.26

يزيل جميع المُستمعين، أو مُستمعي eventName المُحدد.

من غير الممارسات الجيدة إزالة المُستمعين المُضافين في مكان آخر من التعليمات البرمجية، خاصةً عندما تم إنشاء مثيل EventEmitter بواسطة مكون أو وحدة نمطية أخرى (مثل المقابس أو تدفقات الملفات).

يرجع مرجعًا إلى EventEmitter، بحيث يمكن سلسلة المكالمات.

emitter.removeListener(eventName, listener)

مضاف في: v0.1.26

يزيل المُستمع المُحدد listener من مُصفوفة المُستمعين للحدث المسمى eventName.

js
const callback = stream => {
  console.log('someone connected!')
}
server.on('connection', callback)
// ...
server.removeListener('connection', callback)

ستقوم removeListener() بإزالة مثيل واحد على الأكثر من المُستمع من مُصفوفة المُستمعين. إذا تم إضافة أي مُستمع واحد عدة مرات إلى مُصفوفة المُستمعين للحدث المُحدد eventName، فيجب استدعاء removeListener() عدة مرات لإزالة كل مثيل.

بمجرد إصدار حدث ما، يتم استدعاء جميع المُستمعين المُرفقين به في وقت الإصدار بالترتيب. هذا يعني أن أي مكالمات removeListener() أو removeAllListeners() بعد الإصدار وقبل انتهاء تنفيذ آخر مُستمع لن تزيلها من emit() قيد التقدم. تتصرف الأحداث اللاحقة كما هو متوقع.

js
import { EventEmitter } from 'node:events'
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter()

const callbackA = () => {
  console.log('A')
  myEmitter.removeListener('event', callbackB)
}

const callbackB = () => {
  console.log('B')
}

myEmitter.on('event', callbackA)

myEmitter.on('event', callbackB)

// callbackA يزيل المُستمع callbackB لكنه سيتم استدعائه مع ذلك.
// مُصفوفة المُستمعين الداخلية في وقت الإصدار [callbackA, callbackB]
myEmitter.emit('event')
// يُطبع:
//   A
//   B

// تم إزالة callbackB الآن.
// مُصفوفة المُستمعين الداخلية [callbackA]
myEmitter.emit('event')
// يُطبع:
//   A
js
const EventEmitter = require('node:events')
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter()

const callbackA = () => {
  console.log('A')
  myEmitter.removeListener('event', callbackB)
}

const callbackB = () => {
  console.log('B')
}

myEmitter.on('event', callbackA)

myEmitter.on('event', callbackB)

// callbackA يزيل المُستمع callbackB لكنه سيتم استدعائه مع ذلك.
// مُصفوفة المُستمعين الداخلية في وقت الإصدار [callbackA, callbackB]
myEmitter.emit('event')
// يُطبع:
//   A
//   B

// تم إزالة callbackB الآن.
// مُصفوفة المُستمعين الداخلية [callbackA]
myEmitter.emit('event')
// يُطبع:
//   A

لأن المُستمعين يتم إدارتهم باستخدام مُصفوفة داخلية، فإن استدعاء هذا سيُغيّر مؤشرات مواقع أي مُستمع مُسجّل بعد المُستمع الذي تم إزالته. هذا لن يؤثر على الترتيب الذي يتم فيه استدعاء المُستمعين، لكنه يعني أن أي نسخ من مُصفوفة المُستمعين كما هو مُرجع بواسطة طريقة emitter.listeners() ستحتاج إلى إعادة إنشائها.

عندما يتم إضافة دالة واحدة كمعالج عدة مرات لحدث واحد (كما في المثال أدناه)، ستقوم removeListener() بإزالة آخر مثيل تمت إضافته. في المثال، يتم إزالة مُستمع once('ping'):

js
import { EventEmitter } from 'node:events'
const ee = new EventEmitter()

function pong() {
  console.log('pong')
}

ee.on('ping', pong)
ee.once('ping', pong)
ee.removeListener('ping', pong)

ee.emit('ping')
ee.emit('ping')
js
const EventEmitter = require('node:events')
const ee = new EventEmitter()

function pong() {
  console.log('pong')
}

ee.on('ping', pong)
ee.once('ping', pong)
ee.removeListener('ping', pong)

ee.emit('ping')
ee.emit('ping')

يرجع مرجعًا إلى EventEmitter، بحيث يمكن سلسلة المكالمات.

emitter.setMaxListeners(n)

أضيف في: v0.3.5

بشكل افتراضي، ستقوم EventEmitter بطباعة تحذير إذا تم إضافة أكثر من 10 مستمعين لحدث معين. هذا هو الإعداد الافتراضي المفيد الذي يساعد في العثور على تسربات الذاكرة. تسمح طريقة emitter.setMaxListeners() بتعديل الحد لهذه مثيل EventEmitter محدد. يمكن تعيين القيمة إلى Infinity (أو 0) للإشارة إلى عدد غير محدود من المستمعين.

ترجع مرجعًا إلى EventEmitter، بحيث يمكن سلسلة المكالمات.

emitter.rawListeners(eventName)

أضيف في: v9.4.0

ترجع نسخة من مصفوفة المستمعين للحدث المسمى eventName، بما في ذلك أي أغلفة (مثل تلك التي تم إنشاؤها بواسطة .once()).

js
import { EventEmitter } from 'node:events'
const emitter = new EventEmitter()
emitter.once('log', () => console.log('log once'))

// ترجع مصفوفة جديدة مع دالة `onceWrapper` التي تحتوي على خاصية
// `listener` التي تحتوي على المستمع الأصلي المرتبط أعلاه
const listeners = emitter.rawListeners('log')
const logFnWrapper = listeners[0]

// تسجل "log once" على وحدة التحكم ولا تلغي ربط حدث `once`
logFnWrapper.listener()

// تسجل "log once" على وحدة التحكم وتزيل المستمع
logFnWrapper()

emitter.on('log', () => console.log('log persistently'))
// سترجع مصفوفة جديدة مع دالة واحدة مرتبطة بواسطة `.on()` أعلاه
const newListeners = emitter.rawListeners('log')

// تسجل "log persistently" مرتين
newListeners[0]()
emitter.emit('log')
js
const EventEmitter = require('node:events')
const emitter = new EventEmitter()
emitter.once('log', () => console.log('log once'))

// ترجع مصفوفة جديدة مع دالة `onceWrapper` التي تحتوي على خاصية
// `listener` التي تحتوي على المستمع الأصلي المرتبط أعلاه
const listeners = emitter.rawListeners('log')
const logFnWrapper = listeners[0]

// تسجل "log once" على وحدة التحكم ولا تلغي ربط حدث `once`
logFnWrapper.listener()

// تسجل "log once" على وحدة التحكم وتزيل المستمع
logFnWrapper()

emitter.on('log', () => console.log('log persistently'))
// سترجع مصفوفة جديدة مع دالة واحدة مرتبطة بواسطة `.on()` أعلاه
const newListeners = emitter.rawListeners('log')

// تسجل "log persistently" مرتين
newListeners[0]()
emitter.emit('log')

emitter[Symbol.for('nodejs.rejection')](err, eventName[, ...args])

[History]

الإصدارالتغييرات
v17.4.0, v16.14.0لم يعد تجريبيًا.
v13.4.0, v12.16.0تمت الإضافة في: v13.4.0, v12.16.0

يتم استدعاء طريقة Symbol.for('nodejs.rejection') في حالة حدوث رفض وعود عند إصدار حدث وتمكين captureRejections على المُصدر. من الممكن استخدام events.captureRejectionSymbol بدلاً من Symbol.for('nodejs.rejection').

js
import { EventEmitter, captureRejectionSymbol } from 'node:events'

class MyClass extends EventEmitter {
  constructor() {
    super({ captureRejections: true })
  }

  [captureRejectionSymbol](err, event, ...args) {
    console.log('rejection happened for', event, 'with', err, ...args)
    this.destroy(err)
  }

  destroy(err) {
    // قم بإزالة المورد هنا.
  }
}
js
const { EventEmitter, captureRejectionSymbol } = require('node:events')

class MyClass extends EventEmitter {
  constructor() {
    super({ captureRejections: true })
  }

  [captureRejectionSymbol](err, event, ...args) {
    console.log('rejection happened for', event, 'with', err, ...args)
    this.destroy(err)
  }

  destroy(err) {
    // قم بإزالة المورد هنا.
  }
}

events.defaultMaxListeners

تمت الإضافة في: v0.11.2

افتراضيًا، يمكن تسجيل ما يصل إلى 10 مستمعين لأي حدث واحد. يمكن تغيير هذا الحد بالنسبة لمعظم مثيلات EventEmitter باستخدام طريقة emitter.setMaxListeners(n). لتغيير الإعداد الافتراضي لجميع مثيلات EventEmitter، يمكن استخدام خاصية events.defaultMaxListeners. إذا لم تكن هذه القيمة رقمًا موجبًا، فسيتم طرح RangeError.

احرص عند ضبط events.defaultMaxListeners لأن التغيير يؤثر على جميع مثيلات EventEmitter، بما في ذلك تلك التي تم إنشاؤها قبل إجراء التغيير. ومع ذلك، فإن استدعاء emitter.setMaxListeners(n) لا يزال له الأسبقية على events.defaultMaxListeners.

هذا ليس حدًا صارمًا. سيسمح مثيل EventEmitter بإضافة المزيد من المستمعين، لكنه سيخرج تحذير تتبع إلى stderr يشير إلى أنه تم اكتشاف "تسرب محتمل لذاكرة EventEmitter". بالنسبة لأي مثيل EventEmitter واحد، يمكن استخدام طريقتي emitter.getMaxListeners() و emitter.setMaxListeners() لتجنب هذا التحذير مؤقتًا:

لا يؤثر defaultMaxListeners على مثيلات AbortSignal. بينما لا يزال من الممكن استخدام emitter.setMaxListeners(n) لتعيين حد تحذير لمعظم مثيلات AbortSignal، فإن مثيلات AbortSignal بشكل افتراضي لن تُصدر تحذيرًا.

js
import { EventEmitter } from 'node:events'
const emitter = new EventEmitter()
emitter.setMaxListeners(emitter.getMaxListeners() + 1)
emitter.once('event', () => {
  // قم بعمل شيء ما
  emitter.setMaxListeners(Math.max(emitter.getMaxListeners() - 1, 0))
})
js
const EventEmitter = require('node:events')
const emitter = new EventEmitter()
emitter.setMaxListeners(emitter.getMaxListeners() + 1)
emitter.once('event', () => {
  // قم بعمل شيء ما
  emitter.setMaxListeners(Math.max(emitter.getMaxListeners() - 1, 0))
})

يمكن استخدام علم سطر الأوامر --trace-warnings لعرض تتبع المكدس لهذه التحذيرات.

يمكن فحص التحذير الصادر باستخدام process.on('warning') وسيكون له خصائص إضافية emitter و type و count، والتي تشير إلى مثيل مُصدر الحدث، واسم الحدث، وعدد المستمعين المُرفقين، على التوالي. تم تعيين خاصية name الخاصة به إلى 'MaxListenersExceededWarning'.

events.errorMonitor

مضاف في: v13.6.0، v12.17.0

يجب استخدام هذا الرمز لتثبيت مُستمع لمراقبة أحداث 'error' فقط. يتم استدعاء المُستمعين المثبتين باستخدام هذا الرمز قبل استدعاء مُستمعي 'error' العاديين.

إن تثبيت مُستمع باستخدام هذا الرمز لا يُغيّر السلوك بمجرد إصدار حدث 'error'. لذلك، ستظل العملية تتعطل إذا لم يتم تثبيت مُستمع 'error' عادي.

events.getEventListeners(emitterOrTarget, eventName)

مضاف في: v15.2.0، v14.17.0

يُعيد نسخة من مُصفوفة المُستمعين للحدث المُسمّى eventName.

بالنسبة إلى كائنات EventEmitter، فإن هذا يتصرف بالضبط بنفس طريقة استدعاء .listeners على المُصدر.

بالنسبة إلى كائنات EventTarget، هذه هي الطريقة الوحيدة للحصول على مُستمعي الأحداث لكائن الهدف للحدث. هذا مفيد لأغراض تصحيح الأخطاء والتشخيص.

js
import { getEventListeners, EventEmitter } from 'node:events'

{
  const ee = new EventEmitter()
  const listener = () => console.log('Events are fun')
  ee.on('foo', listener)
  console.log(getEventListeners(ee, 'foo')) // [ [Function: listener] ]
}
{
  const et = new EventTarget()
  const listener = () => console.log('Events are fun')
  et.addEventListener('foo', listener)
  console.log(getEventListeners(et, 'foo')) // [ [Function: listener] ]
}
js
const { getEventListeners, EventEmitter } = require('node:events')

{
  const ee = new EventEmitter()
  const listener = () => console.log('Events are fun')
  ee.on('foo', listener)
  console.log(getEventListeners(ee, 'foo')) // [ [Function: listener] ]
}
{
  const et = new EventTarget()
  const listener = () => console.log('Events are fun')
  et.addEventListener('foo', listener)
  console.log(getEventListeners(et, 'foo')) // [ [Function: listener] ]
}

events.getMaxListeners(emitterOrTarget)

تم الإضافة في: v19.9.0، v18.17.0

يرجع الحد الأقصى المحدد حاليًا لكمية المستمعين.

بالنسبة إلى EventEmitter، فإن هذا يتصرف بنفس الطريقة تمامًا مثل الاتصال بـ .getMaxListeners على المُصدر.

بالنسبة إلى EventTarget، هذه هي الطريقة الوحيدة للحصول على الحد الأقصى لمستمعي الحدث لهدف الحدث. إذا تجاوز عدد مُعالجات الأحداث على EventTarget واحد الحد الأقصى المُحدد، فسوف يقوم EventTarget بطباعة تحذير.

js
import { getMaxListeners, setMaxListeners, EventEmitter } from 'node:events'

{
  const ee = new EventEmitter()
  console.log(getMaxListeners(ee)) // 10
  setMaxListeners(11, ee)
  console.log(getMaxListeners(ee)) // 11
}
{
  const et = new EventTarget()
  console.log(getMaxListeners(et)) // 10
  setMaxListeners(11, et)
  console.log(getMaxListeners(et)) // 11
}
js
const { getMaxListeners, setMaxListeners, EventEmitter } = require('node:events')

{
  const ee = new EventEmitter()
  console.log(getMaxListeners(ee)) // 10
  setMaxListeners(11, ee)
  console.log(getMaxListeners(ee)) // 11
}
{
  const et = new EventTarget()
  console.log(getMaxListeners(et)) // 10
  setMaxListeners(11, et)
  console.log(getMaxListeners(et)) // 11
}

events.once(emitter, name[, options])

[History]

الإصدارالتغييرات
v15.0.0خيار signal مدعوم الآن.
v11.13.0، v10.16.0تمت الإضافة في: v11.13.0، v10.16.0

يُنشئ Promise يتم الوفاء به عندما يُصدر EventEmitter الحدث المُعطى أو الذي يتم رفضه إذا أصدر EventEmitter 'error' أثناء الانتظار. سيتم حل Promise مع مصفوفة من جميع الوسائط المُصدرة إلى الحدث المُعطى.

هذه الطريقة عامة بشكل متعمد وتعمل مع واجهة منصة الويب EventTarget، التي ليس لديها دلالات حدث 'error' خاصة ولا تستمع إلى حدث 'error'.

js
import { once, EventEmitter } from 'node:events'
import process from 'node:process'

const ee = new EventEmitter()

process.nextTick(() => {
  ee.emit('myevent', 42)
})

const [value] = await once(ee, 'myevent')
console.log(value)

const err = new Error('kaboom')
process.nextTick(() => {
  ee.emit('error', err)
})

try {
  await once(ee, 'myevent')
} catch (err) {
  console.error('error happened', err)
}
js
const { once, EventEmitter } = require('node:events')

async function run() {
  const ee = new EventEmitter()

  process.nextTick(() => {
    ee.emit('myevent', 42)
  })

  const [value] = await once(ee, 'myevent')
  console.log(value)

  const err = new Error('kaboom')
  process.nextTick(() => {
    ee.emit('error', err)
  })

  try {
    await once(ee, 'myevent')
  } catch (err) {
    console.error('error happened', err)
  }
}

run()

يتم استخدام المعالجة الخاصة لحدث 'error' فقط عندما يتم استخدام events.once() للانتظار لحدث آخر. إذا تم استخدام events.once() للانتظار لحدث 'error' نفسه، فسيتم التعامل معه كأي نوع آخر من الأحداث بدون معالجة خاصة:

js
import { EventEmitter, once } from 'node:events'

const ee = new EventEmitter()

once(ee, 'error')
  .then(([err]) => console.log('ok', err.message))
  .catch(err => console.error('error', err.message))

ee.emit('error', new Error('boom'))

// Prints: ok boom
js
const { EventEmitter, once } = require('node:events')

const ee = new EventEmitter()

once(ee, 'error')
  .then(([err]) => console.log('ok', err.message))
  .catch(err => console.error('error', err.message))

ee.emit('error', new Error('boom'))

// Prints: ok boom

يمكن استخدام <AbortSignal> لإلغاء انتظار الحدث:

js
import { EventEmitter, once } from 'node:events'

const ee = new EventEmitter()
const ac = new AbortController()

async function foo(emitter, event, signal) {
  try {
    await once(emitter, event, { signal })
    console.log('event emitted!')
  } catch (error) {
    if (error.name === 'AbortError') {
      console.error('Waiting for the event was canceled!')
    } else {
      console.error('There was an error', error.message)
    }
  }
}

foo(ee, 'foo', ac.signal)
ac.abort() // Prints: Waiting for the event was canceled!
js
const { EventEmitter, once } = require('node:events')

const ee = new EventEmitter()
const ac = new AbortController()

async function foo(emitter, event, signal) {
  try {
    await once(emitter, event, { signal })
    console.log('event emitted!')
  } catch (error) {
    if (error.name === 'AbortError') {
      console.error('Waiting for the event was canceled!')
    } else {
      console.error('There was an error', error.message)
    }
  }
}

foo(ee, 'foo', ac.signal)
ac.abort() // Prints: Waiting for the event was canceled!

انتظار أحداث متعددة مُطلقة على process.nextTick()

هناك حالة حدية جديرة بالملاحظة عند استخدام دالة events.once() لانتظار أحداث متعددة مُطلقة في نفس دفعة عمليات process.nextTick(), أو كلما تم إطلاق أحداث متعددة بشكل متزامن. على وجه التحديد، نظرًا لأن قائمة انتظار process.nextTick() تُفرغ قبل قائمة المهام الدقيقة Promise، ولأن EventEmitter يُطلق جميع الأحداث بشكل متزامن، فمن الممكن أن يفوّت events.once() حدثًا.

js
import { EventEmitter, once } from 'node:events'
import process from 'node:process'

const myEE = new EventEmitter()

async function foo() {
  await once(myEE, 'bar')
  console.log('bar')

  // لن يتم حل هذا الوعد أبدًا لأن حدث 'foo' سيكون
  // قد تم إطلاقه بالفعل قبل إنشاء الوعد.
  await once(myEE, 'foo')
  console.log('foo')
}

process.nextTick(() => {
  myEE.emit('bar')
  myEE.emit('foo')
})

foo().then(() => console.log('done'))
js
const { EventEmitter, once } = require('node:events')

const myEE = new EventEmitter()

async function foo() {
  await once(myEE, 'bar')
  console.log('bar')

  // لن يتم حل هذا الوعد أبدًا لأن حدث 'foo' سيكون
  // قد تم إطلاقه بالفعل قبل إنشاء الوعد.
  await once(myEE, 'foo')
  console.log('foo')
}

process.nextTick(() => {
  myEE.emit('bar')
  myEE.emit('foo')
})

foo().then(() => console.log('done'))

لالتقاط كلا الحدثين، قم بإنشاء كل من الوعود قبل انتظار أي منهما، ثم يصبح من الممكن استخدام Promise.all(), Promise.race(), أو Promise.allSettled():

js
import { EventEmitter, once } from 'node:events'
import process from 'node:process'

const myEE = new EventEmitter()

async function foo() {
  await Promise.all([once(myEE, 'bar'), once(myEE, 'foo')])
  console.log('foo', 'bar')
}

process.nextTick(() => {
  myEE.emit('bar')
  myEE.emit('foo')
})

foo().then(() => console.log('done'))
js
const { EventEmitter, once } = require('node:events')

const myEE = new EventEmitter()

async function foo() {
  await Promise.all([once(myEE, 'bar'), once(myEE, 'foo')])
  console.log('foo', 'bar')
}

process.nextTick(() => {
  myEE.emit('bar')
  myEE.emit('foo')
})

foo().then(() => console.log('done'))

events.captureRejections

[السجل]

الإصدارالتغييرات
v17.4.0, v16.14.0لم يعد تجريبيًا.
v13.4.0, v12.16.0تمت الإضافة في: v13.4.0، v12.16.0

القيمة: <boolean>

تغيير خيار captureRejections الافتراضي على جميع كائنات EventEmitter الجديدة.

events.captureRejectionSymbol

[السجل]

الإصدارالتغييرات
v17.4.0, v16.14.0لم يعد تجريبيًا.
v13.4.0, v12.16.0تمت الإضافة في: v13.4.0، v12.16.0

القيمة: Symbol.for('nodejs.rejection')

راجع كيفية كتابة مُعالِج رفض مخصص معالج الرفض.

events.listenerCount(emitter, eventName)

تمت الإضافة في: v0.9.12

تم إهماله منذ: v3.2.0

[مستقر: 0 - مهمل]

مستقر: 0 الثبات: 0 - مهمل: استخدم emitter.listenerCount() بدلاً من ذلك.

طريقة فئة تُرجع عدد المُستمعين لاسم الحدث المُعطى المُسجّل على المُرسِل المُعطى.

js
import { EventEmitter, listenerCount } from 'node:events'

const myEmitter = new EventEmitter()
myEmitter.on('event', () => {})
myEmitter.on('event', () => {})
console.log(listenerCount(myEmitter, 'event'))
// يُطبع: 2
js
const { EventEmitter, listenerCount } = require('node:events')

const myEmitter = new EventEmitter()
myEmitter.on('event', () => {})
myEmitter.on('event', () => {})
console.log(listenerCount(myEmitter, 'event'))
// يُطبع: 2

events.on(emitter, eventName[, options])

[History]

الإصدارالتغييرات
v22.0.0, v20.13.0دعم خيارات highWaterMark و lowWaterMark، من أجل الاتساق. لا تزال الخيارات القديمة مدعومة.
v20.0.0يتم دعم خيارات close و highWatermark و lowWatermark الآن.
v13.6.0, v12.16.0تمت الإضافة في: v13.6.0, v12.16.0
  • emitter <EventEmitter>

  • eventName <string> | <symbol> اسم الحدث الذي يتم الاستماع إليه

  • options <Object>

    • signal <AbortSignal> يمكن استخدامه لإلغاء انتظار الأحداث.
    • close - <string[]> أسماء الأحداث التي ستنهي التكرار.
    • highWaterMark - <integer> الافتراضي: Number.MAX_SAFE_INTEGER الحد الأعلى. يتم إيقاف تشغيل المُصدر في كل مرة يكون حجم الأحداث التي يتم تخزينها مؤقتًا أعلى منه. مدعوم فقط على المُصدرين الذين ينفذون طرق pause() و resume().
    • lowWaterMark - <integer> الافتراضي: 1 الحد الأدنى. يتم استئناف تشغيل المُصدر في كل مرة يكون حجم الأحداث التي يتم تخزينها مؤقتًا أقل منه. مدعوم فقط على المُصدرين الذين ينفذون طرق pause() و resume().
  • الإرجاع: <AsyncIterator> الذي يكرر أحداث eventName التي يصدرها emitter

js
import { on, EventEmitter } from 'node:events'
import process from 'node:process'

const ee = new EventEmitter()

// الإصدار لاحقاً
process.nextTick(() => {
  ee.emit('foo', 'bar')
  ee.emit('foo', 42)
})

for await (const event of on(ee, 'foo')) {
  // تنفيذ هذا الكتلة الداخلية متزامن وهو
  // يعالج حدثًا واحدًا في كل مرة (حتى مع await). لا تستخدم
  // إذا كان التنفيذ المتزامن مطلوبًا.
  console.log(event) // يطبع ['bar'] [42]
}
// غير قابل للوصول هنا
js
const { on, EventEmitter } = require('node:events')

;(async () => {
  const ee = new EventEmitter()

  // الإصدار لاحقاً
  process.nextTick(() => {
    ee.emit('foo', 'bar')
    ee.emit('foo', 42)
  })

  for await (const event of on(ee, 'foo')) {
    // تنفيذ هذا الكتلة الداخلية متزامن وهو
    // يعالج حدثًا واحدًا في كل مرة (حتى مع await). لا تستخدم
    // إذا كان التنفيذ المتزامن مطلوبًا.
    console.log(event) // يطبع ['bar'] [42]
  }
  // غير قابل للوصول هنا
})()

يُرجع مُكررًا غير متزامن AsyncIterator يُكرر أحداث eventName. سيتم إرسال استثناء إذا أصدر EventEmitter حدث 'error'. يقوم بإزالة جميع المُستمعين عند الخروج من الحلقة. القيمة التي يتم إرجاعها بواسطة كل تكرار هي مصفوفة تتكون من وسيطات الحدث المُصدر.

يمكن استخدام <AbortSignal> لإلغاء انتظار الأحداث:

js
import { on, EventEmitter } from 'node:events'
import process from 'node:process'

const ac = new AbortController()

;(async () => {
  const ee = new EventEmitter()

  // الإصدار لاحقاً
  process.nextTick(() => {
    ee.emit('foo', 'bar')
    ee.emit('foo', 42)
  })

  for await (const event of on(ee, 'foo', { signal: ac.signal })) {
    // تنفيذ هذا الكتلة الداخلية متزامن وهو
    // يعالج حدثًا واحدًا في كل مرة (حتى مع await). لا تستخدم
    // إذا كان التنفيذ المتزامن مطلوبًا.
    console.log(event) // يطبع ['bar'] [42]
  }
  // غير قابل للوصول هنا
})()

process.nextTick(() => ac.abort())
js
const { on, EventEmitter } = require('node:events')

const ac = new AbortController()

;(async () => {
  const ee = new EventEmitter()

  // الإصدار لاحقاً
  process.nextTick(() => {
    ee.emit('foo', 'bar')
    ee.emit('foo', 42)
  })

  for await (const event of on(ee, 'foo', { signal: ac.signal })) {
    // تنفيذ هذا الكتلة الداخلية متزامن وهو
    // يعالج حدثًا واحدًا في كل مرة (حتى مع await). لا تستخدم
    // إذا كان التنفيذ المتزامن مطلوبًا.
    console.log(event) // يطبع ['bar'] [42]
  }
  // غير قابل للوصول هنا
})()

process.nextTick(() => ac.abort())

events.setMaxListeners(n[, ...eventTargets])

مضاف في: v15.4.0

js
import { setMaxListeners, EventEmitter } from 'node:events'

const target = new EventTarget()
const emitter = new EventEmitter()

setMaxListeners(5, target, emitter)
js
const { setMaxListeners, EventEmitter } = require('node:events')

const target = new EventTarget()
const emitter = new EventEmitter()

setMaxListeners(5, target, emitter)

events.addAbortListener(signal, listener)

مضاف في: v20.5.0، v18.18.0

[مستقر: 1 - تجريبي]

مستقر: 1 استقرار: 1 - تجريبي

يستمع مرة واحدة إلى حدث abort على signal المُقدم.

إن الاستماع إلى حدث abort على إشارات الإلغاء غير آمن وقد يؤدي إلى تسرب الموارد نظرًا لأن طرفًا ثالثًا آخر يحتوي على الإشارة يمكنه استدعاء e.stopImmediatePropagation(). لسوء الحظ، لا يمكن لـ Node.js تغيير هذا لأنه من شأنه أن ينتهك معيار الويب. بالإضافة إلى ذلك، فإن واجهة برمجة التطبيقات الأصلية تجعل من السهل نسيان إزالة المستمعين.

تتيح لك هذه واجهة برمجة التطبيقات استخدام AbortSignal بشكل آمن في واجهات برمجة تطبيقات Node.js من خلال حل هاتين المشكلتين من خلال الاستماع إلى الحدث بحيث لا يمنع stopImmediatePropagation المُستمع من التشغيل.

يُرجع كائنًا قابلًا للتخلص منه بحيث يمكن إلغاء الاشتراك منه بسهولة أكبر.

js
const { addAbortListener } = require('node:events')

function example(signal) {
  let disposable
  try {
    signal.addEventListener('abort', e => e.stopImmediatePropagation())
    disposable = addAbortListener(signal, e => {
      // قم بشيء ما عند إلغاء الإشارة.
    })
  } finally {
    disposable?.[Symbol.dispose]()
  }
}
js
import { addAbortListener } from 'node:events'

function example(signal) {
  let disposable
  try {
    signal.addEventListener('abort', e => e.stopImmediatePropagation())
    disposable = addAbortListener(signal, e => {
      // قم بشيء ما عند إلغاء الإشارة.
    })
  } finally {
    disposable?.[Symbol.dispose]()
  }
}

الصنف: events.EventEmitterAsyncResource extends EventEmitter

مضاف في: v17.4.0، v16.14.0

يدمج EventEmitter مع <AsyncResource> لـ EventEmitter التي تتطلب تتبعًا غير متزامن يدويًا. على وجه التحديد، سيتم تشغيل جميع الأحداث المنبعثة من مثيلات events.EventEmitterAsyncResource ضمن سياقها غير المتزامن.

js
import { EventEmitterAsyncResource, EventEmitter } from 'node:events'
import { notStrictEqual, strictEqual } from 'node:assert'
import { executionAsyncId, triggerAsyncId } from 'node:async_hooks'

// ستحدد أدوات تتبع غير المتزامن هذا على أنه 'Q'.
const ee1 = new EventEmitterAsyncResource({ name: 'Q' })

// سيتم تشغيل مستمعي 'foo' في سياق EventEmitter غير المتزامن.
ee1.on('foo', () => {
  strictEqual(executionAsyncId(), ee1.asyncId)
  strictEqual(triggerAsyncId(), ee1.triggerAsyncId)
})

const ee2 = new EventEmitter()

// ومع ذلك، فإن مستمعي 'foo' على EventEmitters العادية التي لا تتبع السياق غير المتزامن، سيتم تشغيلها في نفس السياق غير المتزامن مثل emit().
ee2.on('foo', () => {
  notStrictEqual(executionAsyncId(), ee2.asyncId)
  notStrictEqual(triggerAsyncId(), ee2.triggerAsyncId)
})

Promise.resolve().then(() => {
  ee1.emit('foo')
  ee2.emit('foo')
})
js
const { EventEmitterAsyncResource, EventEmitter } = require('node:events')
const { notStrictEqual, strictEqual } = require('node:assert')
const { executionAsyncId, triggerAsyncId } = require('node:async_hooks')

// ستحدد أدوات تتبع غير المتزامن هذا على أنه 'Q'.
const ee1 = new EventEmitterAsyncResource({ name: 'Q' })

// سيتم تشغيل مستمعي 'foo' في سياق EventEmitter غير المتزامن.
ee1.on('foo', () => {
  strictEqual(executionAsyncId(), ee1.asyncId)
  strictEqual(triggerAsyncId(), ee1.triggerAsyncId)
})

const ee2 = new EventEmitter()

// ومع ذلك، فإن مستمعي 'foo' على EventEmitters العادية التي لا تتبع السياق غير المتزامن، سيتم تشغيلها في نفس السياق غير المتزامن مثل emit().
ee2.on('foo', () => {
  notStrictEqual(executionAsyncId(), ee2.asyncId)
  notStrictEqual(triggerAsyncId(), ee2.triggerAsyncId)
})

Promise.resolve().then(() => {
  ee1.emit('foo')
  ee2.emit('foo')
})

يحتوي صنف EventEmitterAsyncResource على نفس الطرق ويأخذ نفس الخيارات مثل EventEmitter و AsyncResource أنفسهم.

new events.EventEmitterAsyncResource([options])

  • options <Object>
    • captureRejections <boolean> يمكّن الاستيلاء التلقائي على رفض الوعد. الافتراضي: false.
    • name <string> نوع الحدث غير المتزامن. الافتراضي: new.target.name.
    • triggerAsyncId <number> معرف سياق التنفيذ الذي أنشأ هذا الحدث غير المتزامن. الافتراضي: executionAsyncId().
    • requireManualDestroy <boolean> إذا تم تعيينه على true، فإنه يُعطل emitDestroy عند جمع القمامة للكائن. عادةً لا يلزم تعيين هذا (حتى إذا تم استدعاء emitDestroy يدويًا)، إلا إذا تم استرداد asyncId الخاص بالمورد وتم استدعاء emitDestroy الخاص بواجهة برمجة التطبيقات الحساسة به. عند تعيينه على false، فإن استدعاء emitDestroy عند جمع القمامة سيحدث فقط إذا كان هناك خطاف destroy نشط واحد على الأقل. الافتراضي: false.

eventemitterasyncresource.asyncId

  • النوع: <number> asyncId الفريد المخصص للمورد.

eventemitterasyncresource.asyncResource

يحتوي كائن AsyncResource المُرجَع على خاصية eventEmitter إضافية توفر مرجعًا لهذا EventEmitterAsyncResource.

eventemitterasyncresource.emitDestroy()

استدعاء جميع خطافات destroy. يجب استدعاء هذا مرة واحدة فقط. سيتم طرح خطأ إذا تم استدعائه أكثر من مرة. يجب استدعاء هذا يدويًا. إذا تم ترك المورد ليتم جمعه بواسطة GC، فلن يتم استدعاء خطافات destroy أبدًا.

eventemitterasyncresource.triggerAsyncId

  • نوع: <عدد> نفس triggerAsyncId الذي يتم تمريره إلى مُنشئ AsyncResource.

واجهة برمجة التطبيقات EventTarget و Event

[السجل]

الإصدارالتغييرات
v16.0.0تم تغيير معالجة أخطاء EventTarget.
v15.4.0لم تعد تجريبية.
v15.0.0أصبحت فئتا EventTarget و Event متاحتين الآن كمتغيرات عالمية.
v14.5.0تمت الإضافة في: v14.5.0

كائنا EventTarget و Event هما تنفيذ محدد بنظام Node.js لواجهة برمجة التطبيقات EventTarget Web API التي تعرضها بعض واجهات برمجة التطبيقات الأساسية لنظام Node.js.

js
const target = new EventTarget()

target.addEventListener('foo', event => {
  console.log('حدث حدث foo!')
})

EventTarget لنظام Node.js مقابل EventTarget لواجهة برمجة تطبيقات المستندات

هناك فرقين رئيسيين بين EventTarget لنظام Node.js وواجهة برمجة التطبيقات EventTarget Web API:

NodeEventTarget مقابل EventEmitter

يُنفذ كائن NodeEventTarget مجموعة فرعية معدلة من واجهة برمجة التطبيقات EventEmitter التي تسمح له بـ محاكاة EventEmitter بشكل وثيق في بعض المواقف. NodeEventTarget ليس مثيلًا لـ EventEmitter ولا يمكن استخدامه بدلاً من EventEmitter في معظم الحالات.

مُستمع الحدث

قد تكون مُستمعات الأحداث المسجلة لنوع حدث type إما دوال جافا سكريبت أو كائنات ذات خاصية handleEvent قيمةُها دالة.

في كلتا الحالتين، يتم استدعاء دالة المُعالِج مع وسيطة event المُمرّرة إلى دالة eventTarget.dispatchEvent().

يمكن استخدام الدوال غير المتزامنة كمُستمعات أحداث. إذا رفضت دالة مُعالِج غير متزامنة، يتم التقاط الرفض ومعالجته كما هو موضح في معالجة أخطاء EventTarget.

لا يمنع حدوث خطأ يُلقى بواسطة دالة مُعالِج واحدة من استدعاء المُعالجات الأخرى.

يتم تجاهل قيمة الإرجاع لدالة المُعالِج.

يتم دائمًا استدعاء المُعالجات بالترتيب الذي تمت إضافتها به.

قد تُغيّر دوال المُعالِج كائن event.

js
function handler1(event) {
  console.log(event.type) // يطبع 'foo'
  event.a = 1
}

async function handler2(event) {
  console.log(event.type) // يطبع 'foo'
  console.log(event.a) // يطبع 1
}

const handler3 = {
  handleEvent(event) {
    console.log(event.type) // يطبع 'foo'
  },
}

const handler4 = {
  async handleEvent(event) {
    console.log(event.type) // يطبع 'foo'
  },
}

const target = new EventTarget()

target.addEventListener('foo', handler1)
target.addEventListener('foo', handler2)
target.addEventListener('foo', handler3)
target.addEventListener('foo', handler4, { once: true })

معالجة أخطاء EventTarget

عندما يُلقِي مستمع حدث مسجل (أو يُرجع وعدًا يُرفض)، يتم التعامل مع الخطأ افتراضيًا كاستثناء غير معالج على process.nextTick() . هذا يعني أن الاستثناءات غير المعالجة في EventTarget ستنهي عملية Node.js افتراضيًا.

لن يؤدي الإلقاء داخل مستمع الحدث إلى إيقاف استدعاء المُعالجات المسجلة الأخرى.

لا يُنفذ EventTarget أي معالجة افتراضية خاصة لأحداث النوع 'error' مثل EventEmitter.

يتم حاليًا توجيه الأخطاء أولاً إلى حدث process.on('error') قبل الوصول إلى process.on('uncaughtException'). هذا السلوك قديم وسيتغير في إصدار مستقبلي لمواءمة EventTarget مع واجهات برمجة التطبيقات الأخرى في Node.js. يجب أن يتم مواءمة أي رمز يعتمد على حدث process.on('error') مع السلوك الجديد.

الصف: Event

[السجل]

الإصدارالتغييرات
v15.0.0أصبح الصف Event متاحًا الآن من خلال الكائن العام.
v14.5.0تمت الإضافة في: v14.5.0

كائن Event هو تكيف لـ واجهة برمجة تطبيقات الويب Event. يتم إنشاء مثيلات داخليًا بواسطة Node.js.

event.bubbles

تمت الإضافة في: v14.5.0

  • النوع: <boolean> يُرجع دائمًا false.

لا يتم استخدام هذا في Node.js ويتم توفيره فقط من أجل الإتمام.

event.cancelBubble

تمت الإضافة في: v14.5.0

[مستقر: 3 - تراثي]

مستقر: 3 الثبات: 3 - تراثي: استخدم event.stopPropagation() بدلاً من ذلك.

مرادف لـ event.stopPropagation() إذا تم تعيينه على true. لا يتم استخدام هذا في Node.js ويتم توفيره فقط من أجل الإتمام.

event.cancelable

تمت الإضافة في: v14.5.0

  • النوع: <boolean> صحيح إذا تم إنشاء الحدث باستخدام خيار cancelable.

event.composed

تم الإضافة في: v14.5.0

  • النوع: <boolean> يعيد دائمًا false.

لا يُستخدم هذا في Node.js، وهو مُقدم فقط من أجل الإكتمال.

event.composedPath()

تم الإضافة في: v14.5.0

يعيد مصفوفة تحتوي على EventTarget الحالي كمدخل وحيد أو فارغة إذا لم يتم إرسال الحدث. لا يُستخدم هذا في Node.js، وهو مُقدم فقط من أجل الإكتمال.

event.currentTarget

تم الإضافة في: v14.5.0

  • النوع: <EventTarget> EventTarget الذي يُرسل الحدث.

مرادف لـ event.target.

event.defaultPrevented

تم الإضافة في: v14.5.0

يكون true إذا كان cancelable true وتم استدعاء event.preventDefault().

event.eventPhase

تم الإضافة في: v14.5.0

  • النوع: <number> يعيد 0 بينما لا يتم إرسال حدث، 2 بينما يتم إرساله.

لا يُستخدم هذا في Node.js، وهو مُقدم فقط من أجل الإكتمال.

event.initEvent(type[, bubbles[, cancelable]])

تم الإضافة في: v19.5.0

[مستقر: 3 - تراثي]

مستقر: 3 الثبات: 3 - تراثي: تعتبر مواصفات WHATWG أنها مُهملة ويجب على المستخدمين عدم استخدامها على الإطلاق.

مُتكرر مع منشئي الأحداث وغير قادر على ضبط composed. لا يُستخدم هذا في Node.js، وهو مُقدم فقط من أجل الإكتمال.

event.isTrusted

تم الإضافة في: v14.5.0

يتم إرسال حدث <AbortSignal> "abort" مع ضبط isTrusted على true. القيمة هي false في جميع الحالات الأخرى.

event.preventDefault()

أضيف في: v14.5.0

يُعيّن خاصية defaultPrevented إلى true إذا كانت cancelable تساوي true.

event.returnValue

أضيف في: v14.5.0

[مستقر: 3 - مُوروث]

مستقر: 3 استقرار: 3 - مُوروث: استخدم event.defaultPrevented بدلاً منه.

  • النوع: <boolean> صحيح إذا لم يتم إلغاء الحدث.

قيمة event.returnValue هي دائماً عكس event.defaultPrevented. لا يتم استخدام هذا في Node.js وهو مُقدّم فقط من أجل الإكتمال.

event.srcElement

أضيف في: v14.5.0

[مستقر: 3 - مُوروث]

مستقر: 3 استقرار: 3 - مُوروث: استخدم event.target بدلاً منه.

  • النوع: <EventTarget> EventTarget الذي يُرسل الحدث.

مرادف لـ event.target.

event.stopImmediatePropagation()

أضيف في: v14.5.0

يُوقف تنفيذ مُستمعي الأحداث بعد إكمال المُستمع الحالي.

event.stopPropagation()

أضيف في: v14.5.0

لا يتم استخدام هذا في Node.js وهو مُقدّم فقط من أجل الإكتمال.

event.target

أضيف في: v14.5.0

  • النوع: <EventTarget> EventTarget الذي يُرسل الحدث.

event.timeStamp

أضيف في: v14.5.0

الزمن المُؤقت بالميلي ثانية عند إنشاء كائن Event.

event.type

أضيف في: v14.5.0

معرّف نوع الحدث.

الصف: EventTarget

[السجل]

الإصدارالتغييرات
v15.0.0أصبح EventTarget متاحاً الآن من خلال الكائن العام.
v14.5.0أضيف في: v14.5.0

eventTarget.addEventListener(type, listener[, options])

[السجل]

الإصدارالتغييرات
v15.4.0إضافة دعم لخيار signal.
v14.5.0تمت الإضافة في: v14.5.0
  • type <سلسلة>
  • listener <دالة> | <EventListener>
  • options <كائن>
    • once <قيمة منطقية> عندما تكون true، تتم إزالة المُستمع تلقائيًا عند استدعائه لأول مرة. الافتراضي: false.
    • passive <قيمة منطقية> عندما تكون true، تعمل كإشارة على أن المُستمع لن يستدعي طريقة preventDefault() الخاصة بكائن Event. الافتراضي: false.
    • capture <قيمة منطقية> لا يتم استخدامها مباشرةً بواسطة Node.js. تمت إضافتها لإكمال واجهة برمجة التطبيقات. الافتراضي: false.
    • signal <AbortSignal> سيتم إزالة المُستمع عندما يتم استدعاء طريقة abort() الخاصة بكائن AbortSignal المُعطى.

يضيف مُعالجًا جديدًا لحدث type. يتم إضافة أي مُستمع مُعطى مرة واحدة فقط لكل قيمة type و لكل قيمة خيار capture.

إذا كان خيار once يساوي true، فسيتم إزالة listener بعد المرة التالية التي يتم فيها إرسال حدث type.

لا يستخدم خيار capture بواسطة Node.js بأي طريقة وظيفية بخلاف تتبع مُستمعي الأحداث المسجلين وفقًا لمواصفات EventTarget. على وجه التحديد، يتم استخدام خيار capture كجزء من المفتاح عند تسجيل listener. يمكن إضافة أي listener فردي مرة واحدة مع capture = false، ومرة واحدة مع capture = true.

js
function handler(event) {}

const target = new EventTarget()
target.addEventListener('foo', handler, { capture: true }) // الأول
target.addEventListener('foo', handler, { capture: false }) // الثاني

// يقوم بإزالة مثيل المُستمع الثاني
target.removeEventListener('foo', handler)

// يقوم بإزالة مثيل المُستمع الأول
target.removeEventListener('foo', handler, { capture: true })

eventTarget.dispatchEvent(event)

أضيف في: v14.5.0

  • event <Event>
  • القيمة المُرجعه: <boolean> true إذا كانت قيمة سمة cancelable للحدث خاطئة أو لم يتم استدعاء أسلوبه preventDefault()، وإلا فإن القيمة المُرجعه ستكون false.

يرسل الحدث event إلى قائمة المُعالجات لـ event.type.

يتم استدعاء مُستمعي الأحداث المسجلين بشكل متزامن بالترتيب الذي تم تسجيلهم به.

eventTarget.removeEventListener(type, listener[, options])

أضيف في: v14.5.0

يزيل listener من قائمة المُعالجات للحدث type.

الصنف: CustomEvent

[السجل]

الإصدارالتغييرات
v23.0.0لم يعد تجريبيًا.
v22.1.0, v20.13.0أصبح CustomEvent الآن مستقرًا.
v19.0.0لم يعد وراء علم CLI --experimental-global-customevent.
v18.7.0, v16.17.0أضيف في: v18.7.0, v16.17.0

[مستقر: 2 - مستقر]

مستقر: 2 الثبات: 2 - مستقر

كائن CustomEvent هو تكيف لـ CustomEvent واجهة برمجة تطبيقات الويب. يتم إنشاء المثيلات داخليًا بواسطة Node.js.

event.detail

[السجل]

الإصدارالتغييرات
v22.1.0, v20.13.0أصبح CustomEvent الآن مستقرًا.
v18.7.0, v16.17.0أضيف في: v18.7.0, v16.17.0

[مستقر: 2 - مستقر]

مستقر: 2 الثبات: 2 - مستقر

  • النوع: <any> يُرجع البيانات المخصصة التي تم تمريرها عند البدء.

قراءة فقط.

صنف: NodeEventTarget

مضاف في: v14.5.0

NodeEventTarget هو امتداد محدد بنظام Node.js لـ EventTarget يحاكي مجموعة فرعية من واجهة برمجة التطبيقات EventEmitter.

nodeEventTarget.addListener(type, listener)

مضاف في: v14.5.0

امتداد محدد بنظام Node.js إلى صنف EventTarget يحاكي واجهة برمجة التطبيقات EventEmitter المكافئة. الفرق الوحيد بين addListener() و addEventListener() هو أن addListener() ستعيد مرجعًا إلى EventTarget.

nodeEventTarget.emit(type, arg)

مضاف في: v15.2.0

  • type <string>
  • arg <any>
  • يعيد: <boolean> true إذا وجدت مستمعو الأحداث المسجّلون لنوع type، وإلا false.

امتداد محدد بنظام Node.js إلى صنف EventTarget يرسل arg إلى قائمة مُعالجي type.

nodeEventTarget.eventNames()

مضاف في: v14.5.0

امتداد محدد بنظام Node.js إلى صنف EventTarget يعيد مصفوفة من أسماء أنواع الأحداث التي تم تسجيل مستمعي الأحداث لها.

nodeEventTarget.listenerCount(type)

مضاف في: v14.5.0

امتداد محدد بنظام Node.js إلى صنف EventTarget يعيد عدد مستمعي الأحداث المسجّلين لنوع type.

nodeEventTarget.setMaxListeners(n)

مضاف في: v14.5.0

امتداد محدد بـ Node.js لـفئة EventTarget يحدد عدد مستمعي الحدث الأقصى كـ n.

nodeEventTarget.getMaxListeners()

مضاف في: v14.5.0

امتداد محدد بـ Node.js لـفئة EventTarget يُرجع عدد مستمعي الحدث الأقصى.

nodeEventTarget.off(type, listener[, options])

مضاف في: v14.5.0

اسم مستعار محدد بـ Node.js لـ eventTarget.removeEventListener().

nodeEventTarget.on(type, listener)

مضاف في: v14.5.0

اسم مستعار محدد بـ Node.js لـ eventTarget.addEventListener().

nodeEventTarget.once(type, listener)

مضاف في: v14.5.0

امتداد محدد بـ Node.js لـفئة EventTarget يضيف مستمع once لحدث type المُعطى. هذا ما يعادل استدعاء on مع تعيين خيار once إلى true.

nodeEventTarget.removeAllListeners([type])

مضاف في: v14.5.0

امتداد محدد بـ Node.js لفئة EventTarget. إذا تم تحديد type، فسيتم إزالة جميع المُستمعين المسجلين لـ type، وإلا فسيتم إزالة جميع المُستمعين المسجلين.

nodeEventTarget.removeListener(type, listener[, options])

مضاف في: v14.5.0

امتداد محدد بـ Node.js لفئة EventTarget يُزيل listener لـ type المُعطى. الفرق الوحيد بين removeListener() و removeEventListener() هو أن removeListener() ستُرجع مرجعًا لـ EventTarget.