Skip to content

Eventi

[Stabile: 2 - Stabile]

Stabile: 2 Stabilità: 2 - Stabile

Codice sorgente: lib/events.js

Gran parte dell'API core di Node.js è costruita attorno a un'architettura idiomatica asincrona guidata dagli eventi in cui determinati tipi di oggetti (chiamati "emettitori") emettono eventi denominati che causano la chiamata di oggetti Function ("listener").

Ad esempio: un oggetto net.Server emette un evento ogni volta che un peer si connette ad esso; un fs.ReadStream emette un evento quando il file viene aperto; uno stream emette un evento ogni volta che sono disponibili dati da leggere.

Tutti gli oggetti che emettono eventi sono istanze della classe EventEmitter. Questi oggetti espongono una funzione eventEmitter.on() che consente di collegare una o più funzioni a eventi denominati emessi dall'oggetto. In genere, i nomi degli eventi sono stringhe in formato camel-case, ma è possibile utilizzare qualsiasi chiave di proprietà JavaScript valida.

Quando l'oggetto EventEmitter emette un evento, tutte le funzioni collegate a quello specifico evento vengono chiamate sincronamente. Qualsiasi valore restituito dai listener chiamati viene ignorato e scartato.

L'esempio seguente mostra una semplice istanza di EventEmitter con un singolo listener. Il metodo eventEmitter.on() viene utilizzato per registrare i listener, mentre il metodo eventEmitter.emit() viene utilizzato per attivare l'evento.

js
import { EventEmitter } from 'node:events'

class MyEmitter extends EventEmitter {}

const myEmitter = new MyEmitter()
myEmitter.on('event', () => {
  console.log('si è verificato un evento!')
})
myEmitter.emit('event')
js
const EventEmitter = require('node:events')

class MyEmitter extends EventEmitter {}

const myEmitter = new MyEmitter()
myEmitter.on('event', () => {
  console.log('si è verificato un evento!')
})
myEmitter.emit('event')

Passaggio di argomenti e this ai listener

Il metodo eventEmitter.emit() consente di passare un set arbitrario di argomenti alle funzioni listener. Tieni presente che quando viene chiamata una normale funzione listener, la parola chiave standard this viene intenzionalmente impostata in modo da fare riferimento all'istanza EventEmitter a cui è collegato il listener.

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)
  // Stampa:
  //   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)
  // Stampa:
  //   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')

È possibile utilizzare le Funzioni Freccia ES6 come listener, tuttavia, in tal caso, la parola chiave this non farà più riferimento all'istanza 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)
  // Stampa: 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)
  // Stampa: a b {}
})
myEmitter.emit('event', 'a', 'b')

Asincrono vs. sincrono

L'EventEmitter chiama tutti i listener in modo sincrono nell'ordine in cui sono stati registrati. Ciò garantisce la corretta sequenza degli eventi e aiuta a evitare race condition ed errori logici. Quando appropriato, le funzioni listener possono passare a una modalità di funzionamento asincrona utilizzando i metodi setImmediate() o process.nextTick():

js
import { EventEmitter } from 'node:events'
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter()
myEmitter.on('event', (a, b) => {
  setImmediate(() => {
    console.log('questo avviene in modo asincrono')
  })
})
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('questo avviene in modo asincrono')
  })
})
myEmitter.emit('event', 'a', 'b')

Gestione degli eventi una sola volta

Quando un listener viene registrato utilizzando il metodo eventEmitter.on(), tale listener viene invocato ogni volta che viene emesso l'evento specificato.

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')
// Stampa: 1
myEmitter.emit('event')
// Stampa: 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')
// Stampa: 1
myEmitter.emit('event')
// Stampa: 2

Utilizzando il metodo eventEmitter.once(), è possibile registrare un listener che viene chiamato al massimo una volta per un determinato evento. Una volta che l'evento viene emesso, il listener viene deregistrato e poi chiamato.

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')
// Stampa: 1
myEmitter.emit('event')
// Ignorato
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')
// Stampa: 1
myEmitter.emit('event')
// Ignorato

Eventi di errore

Quando si verifica un errore all'interno di un'istanza di EventEmitter, l'azione tipica è che venga emesso un evento 'error'. Questi sono trattati come casi speciali all'interno di Node.js.

Se un EventEmitter non ha almeno un listener registrato per l'evento 'error', e viene emesso un evento 'error', l'errore viene lanciato, viene stampato uno stack trace e il processo Node.js termina.

js
import { EventEmitter } from 'node:events'
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter()
myEmitter.emit('error', new Error('whoops!'))
// Lancia un'eccezione e blocca Node.js
js
const EventEmitter = require('node:events')
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter()
myEmitter.emit('error', new Error('whoops!'))
// Lancia un'eccezione e blocca Node.js

Per proteggersi dal blocco del processo Node.js, è possibile utilizzare il modulo domain. (Si noti, tuttavia, che il modulo node:domain è deprecato.)

Come buona pratica, i listener dovrebbero sempre essere aggiunti per gli eventi 'error'.

js
import { EventEmitter } from 'node:events'
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter()
myEmitter.on('error', err => {
  console.error('whoops! si è verificato un errore')
})
myEmitter.emit('error', new Error('whoops!'))
// Stampa: whoops! si è verificato un errore
js
const EventEmitter = require('node:events')
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter()
myEmitter.on('error', err => {
  console.error('whoops! si è verificato un errore')
})
myEmitter.emit('error', new Error('whoops!'))
// Stampa: whoops! si è verificato un errore

È possibile monitorare gli eventi 'error' senza consumare l'errore emesso installando un listener utilizzando il simbolo 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!'))
// Lancia comunque un'eccezione e blocca 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!'))
// Lancia comunque un'eccezione e blocca Node.js

Catturare i rifiuti delle promise

L'utilizzo di funzioni async con i gestori di eventi è problematico, perché può portare a un rifiuto non gestito in caso di eccezione generata:

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')
})

L'opzione captureRejections nel costruttore EventEmitter o l'impostazione globale cambiano questo comportamento, installando un gestore .then(undefined, handler) sulla Promise. Questo gestore indirizza l'eccezione in modo asincrono al metodo Symbol.for('nodejs.rejection') se presente, o al gestore eventi 'error' se non presente.

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

Impostando events.captureRejections = true si cambierà il valore predefinito per tutte le nuove istanze di 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)

Gli eventi 'error' che vengono generati dal comportamento captureRejections non hanno un gestore catch per evitare loop di errore infiniti: la raccomandazione è di non usare funzioni async come gestori di eventi 'error'.

Classe: EventEmitter

[Cronologia]

VersioneCambiamenti
v13.4.0, v12.16.0Aggiunta l'opzione captureRejections.
v0.1.26Aggiunta in: v0.1.26

La classe EventEmitter è definita ed esposta dal modulo node:events:

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

Tutti gli EventEmitter emettono l'evento 'newListener' quando vengono aggiunti nuovi listener e 'removeListener' quando i listener esistenti vengono rimossi.

Supporta le seguenti opzioni:

Evento: 'newListener'

Aggiunto in: v0.1.26

L'istanza EventEmitter emetterà il proprio evento 'newListener' prima che un listener venga aggiunto al suo array interno di listener.

Ai listener registrati per l'evento 'newListener' vengono passati il nome dell'evento e un riferimento al listener che viene aggiunto.

Il fatto che l'evento venga attivato prima di aggiungere il listener ha un effetto collaterale sottile ma importante: eventuali listener aggiuntivi registrati con lo stesso name all'interno del callback 'newListener' vengono inseriti prima del listener che è in fase di aggiunta.

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

const myEmitter = new MyEmitter()
// Esegui questo solo una volta per non andare in loop all'infinito
myEmitter.once('newListener', (event, listener) => {
  if (event === 'event') {
    // Inserisci un nuovo listener davanti
    myEmitter.on('event', () => {
      console.log('B')
    })
  }
})
myEmitter.on('event', () => {
  console.log('A')
})
myEmitter.emit('event')
// Stampa:
//   B
//   A
js
const EventEmitter = require('node:events')
class MyEmitter extends EventEmitter {}

const myEmitter = new MyEmitter()
// Esegui questo solo una volta per non andare in loop all'infinito
myEmitter.once('newListener', (event, listener) => {
  if (event === 'event') {
    // Inserisci un nuovo listener davanti
    myEmitter.on('event', () => {
      console.log('B')
    })
  }
})
myEmitter.on('event', () => {
  console.log('A')
})
myEmitter.emit('event')
// Stampa:
//   B
//   A

Evento: 'removeListener'

[Cronologia]

VersioneModifiche
v6.1.0, v4.7.0Per i listener collegati usando .once(), l'argomento listener ora restituisce la funzione listener originale.
v0.9.3Aggiunto in: v0.9.3

L'evento 'removeListener' viene emesso dopo che il listener viene rimosso.

emitter.addListener(eventName, listener)

Aggiunto in: v0.1.26

Alias per emitter.on(eventName, listener).

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

Aggiunto in: v0.1.26

Chiama in modo sincrono ciascuno dei listener registrati per l'evento denominato eventName, nell'ordine in cui sono stati registrati, passando a ciascuno gli argomenti forniti.

Restituisce true se l'evento aveva listener, false altrimenti.

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

// Primo listener
myEmitter.on('event', function firstListener() {
  console.log('Ciao! primo listener')
})
// Secondo listener
myEmitter.on('event', function secondListener(arg1, arg2) {
  console.log(`evento con parametri ${arg1}, ${arg2} nel secondo listener`)
})
// Terzo listener
myEmitter.on('event', function thirdListener(...args) {
  const parameters = args.join(', ')
  console.log(`evento con parametri ${parameters} nel terzo listener`)
})

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

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

// Stampa:
// [
//   [Function: firstListener],
//   [Function: secondListener],
//   [Function: thirdListener]
// ]
// Ciao! primo listener
// evento con parametri 1, 2 nel secondo listener
// evento con parametri 1, 2, 3, 4, 5 nel terzo listener
js
const EventEmitter = require('node:events')
const myEmitter = new EventEmitter()

// Primo listener
myEmitter.on('event', function firstListener() {
  console.log('Ciao! primo listener')
})
// Secondo listener
myEmitter.on('event', function secondListener(arg1, arg2) {
  console.log(`evento con parametri ${arg1}, ${arg2} nel secondo listener`)
})
// Terzo listener
myEmitter.on('event', function thirdListener(...args) {
  const parameters = args.join(', ')
  console.log(`evento con parametri ${parameters} nel terzo listener`)
})

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

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

// Stampa:
// [
//   [Function: firstListener],
//   [Function: secondListener],
//   [Function: thirdListener]
// ]
// Ciao! primo listener
// evento con parametri 1, 2 nel secondo listener
// evento con parametri 1, 2, 3, 4, 5 nel terzo listener

emitter.eventNames()

Aggiunto in: v6.0.0

Restituisce un array che elenca gli eventi per i quali l'emitter ha registrato dei listener. I valori nell'array sono stringhe o 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())
// Stampa: [ '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())
// Stampa: [ 'foo', 'bar', Symbol(symbol) ]

emitter.getMaxListeners()

Aggiunto in: v1.0.0

Restituisce il valore massimo corrente dei listener per l'EventEmitter che è impostato da emitter.setMaxListeners(n) o per impostazione predefinita a events.defaultMaxListeners.

emitter.listenerCount(eventName[, listener])

[Cronologia]

VersioneCambiamenti
v19.8.0, v18.16.0Aggiunto l'argomento listener.
v3.2.0Aggiunto in: v3.2.0

Restituisce il numero di listener in ascolto per l'evento denominato eventName. Se viene fornito listener, restituirà quante volte il listener viene trovato nell'elenco dei listener dell'evento.

emitter.listeners(eventName)

[Cronologia]

VersioneModifiche
v7.0.0Per i listener allegati usando .once() ora restituisce i listener originali invece delle funzioni wrapper.
v0.1.26Aggiunto in: v0.1.26

Restituisce una copia dell'array di listener per l'evento denominato eventName.

js
server.on('connection', stream => {
  console.log('qualcuno si è connesso!')
})
console.log(util.inspect(server.listeners('connection')))
// Stampa: [ [Function] ]

emitter.off(eventName, listener)

Aggiunto in: v10.0.0

Alias per emitter.removeListener().

emitter.on(eventName, listener)

Aggiunto in: v0.1.101

Aggiunge la funzione listener alla fine dell'array dei listener per l'evento denominato eventName. Non vengono effettuati controlli per verificare se il listener è già stato aggiunto. Chiamate multiple che passano la stessa combinazione di eventName e listener comporteranno l'aggiunta e la chiamata del listener più volte.

js
server.on('connection', stream => {
  console.log('qualcuno si è connesso!')
})

Restituisce un riferimento a EventEmitter, in modo che le chiamate possano essere concatenate.

Per impostazione predefinita, i listener di eventi vengono richiamati nell'ordine in cui sono stati aggiunti. Il metodo emitter.prependListener() può essere utilizzato in alternativa per aggiungere il listener di eventi all'inizio dell'array dei listener.

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')
// Stampa:
//   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')
// Stampa:
//   b
//   a

emitter.once(eventName, listener)

Aggiunto in: v0.3.0

Aggiunge una funzione listener una tantum per l'evento chiamato eventName. La prossima volta che eventName viene attivato, questo listener viene rimosso e quindi invocato.

js
server.once('connection', stream => {
  console.log('Ah, abbiamo il nostro primo utente!')
})

Restituisce un riferimento all'EventEmitter, in modo che le chiamate possano essere concatenate.

Per impostazione predefinita, i listener di eventi vengono invocati nell'ordine in cui vengono aggiunti. Il metodo emitter.prependOnceListener() può essere utilizzato in alternativa per aggiungere il listener di eventi all'inizio dell'array dei listener.

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')
// Stampa:
//   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')
// Stampa:
//   b
//   a

emitter.prependListener(eventName, listener)

Aggiunto in: v6.0.0

Aggiunge la funzione listener all'inizio dell'array dei listener per l'evento chiamato eventName. Non vengono effettuati controlli per verificare se il listener è già stato aggiunto. Più chiamate che passano la stessa combinazione di eventName e listener comporteranno l'aggiunta e la chiamata del listener più volte.

js
server.prependListener('connection', stream => {
  console.log('qualcuno si è connesso!')
})

Restituisce un riferimento all'EventEmitter, in modo che le chiamate possano essere concatenate.

emitter.prependOnceListener(eventName, listener)

Aggiunto in: v6.0.0

Aggiunge una funzione listener una tantum per l'evento denominato eventName all'inizio dell'array dei listener. La prossima volta che viene attivato eventName, questo listener viene rimosso e quindi invocato.

js
server.prependOnceListener('connection', stream => {
  console.log('Ah, abbiamo il nostro primo utente!')
})

Restituisce un riferimento all'EventEmitter, in modo che le chiamate possano essere concatenate.

emitter.removeAllListeners([eventName])

Aggiunto in: v0.1.26

Rimuove tutti i listener, o quelli dello specifico eventName.

È una cattiva pratica rimuovere i listener aggiunti altrove nel codice, in particolare quando l'istanza EventEmitter è stata creata da un altro componente o modulo (ad es. socket o flussi di file).

Restituisce un riferimento all'EventEmitter, in modo che le chiamate possano essere concatenate.

emitter.removeListener(eventName, listener)

Aggiunto in: v0.1.26

Rimuove lo specifico listener dall'array dei listener per l'evento denominato eventName.

js
const callback = stream => {
  console.log('qualcuno si è connesso!')
}
server.on('connection', callback)
// ...
server.removeListener('connection', callback)

removeListener() rimuoverà, al massimo, un'istanza di un listener dall'array dei listener. Se un singolo listener è stato aggiunto più volte all'array dei listener per lo specifico eventName, allora removeListener() deve essere chiamato più volte per rimuovere ogni istanza.

Una volta che un evento viene emesso, tutti i listener ad esso collegati al momento dell'emissione vengono chiamati in ordine. Ciò implica che qualsiasi chiamata removeListener() o removeAllListeners() dopo l'emissione e prima che l'ultimo listener termini l'esecuzione non li rimuoverà da emit() in corso. Gli eventi successivi si comportano come previsto.

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 rimuove il listener callbackB ma verrà comunque chiamato.
// Array dei listener interno al momento dell'emissione [callbackA, callbackB]
myEmitter.emit('event')
// Stampa:
//   A
//   B

// callbackB è stato rimosso.
// Array dei listener interno [callbackA]
myEmitter.emit('event')
// Stampa:
//   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 rimuove il listener callbackB ma verrà comunque chiamato.
// Array dei listener interno al momento dell'emissione [callbackA, callbackB]
myEmitter.emit('event')
// Stampa:
//   A
//   B

// callbackB è stato rimosso.
// Array dei listener interno [callbackA]
myEmitter.emit('event')
// Stampa:
//   A

Poiché i listener vengono gestiti utilizzando un array interno, la chiamata a questo cambierà gli indici di posizione di qualsiasi listener registrato dopo il listener che viene rimosso. Ciò non influenzerà l'ordine in cui vengono chiamati i listener, ma significa che qualsiasi copia dell'array dei listener restituita dal metodo emitter.listeners() dovrà essere ricreata.

Quando una singola funzione è stata aggiunta come gestore più volte per un singolo evento (come nell'esempio seguente), removeListener() rimuoverà l'istanza aggiunta più di recente. Nell'esempio viene rimosso il listener 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')

Restituisce un riferimento all'EventEmitter, in modo che le chiamate possano essere concatenate.

emitter.setMaxListeners(n)

Aggiunto in: v0.3.5

Per impostazione predefinita, gli EventEmitter visualizzeranno un avviso se vengono aggiunti più di 10 listener per un particolare evento. Questa è un'impostazione predefinita utile che aiuta a trovare perdite di memoria. Il metodo emitter.setMaxListeners() consente di modificare il limite per questa specifica istanza di EventEmitter. Il valore può essere impostato su Infinity (o 0) per indicare un numero illimitato di listener.

Restituisce un riferimento a EventEmitter, in modo che le chiamate possano essere concatenate.

emitter.rawListeners(eventName)

Aggiunto in: v9.4.0

Restituisce una copia dell'array di listener per l'evento denominato eventName, inclusi eventuali wrapper (come quelli creati da .once()).

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

// Restituisce un nuovo Array con una funzione `onceWrapper` che ha una proprietà
// `listener` che contiene il listener originale collegato sopra
const listeners = emitter.rawListeners('log')
const logFnWrapper = listeners[0]

// Registra "log once" nella console e non scollegare l'evento `once`
logFnWrapper.listener()

// Registra "log once" nella console e rimuove il listener
logFnWrapper()

emitter.on('log', () => console.log('log persistently'))
// Restituirà un nuovo Array con una singola funzione collegata da `.on()` sopra
const newListeners = emitter.rawListeners('log')

// Registra "log persistently" due volte
newListeners[0]()
emitter.emit('log')
js
const EventEmitter = require('node:events')
const emitter = new EventEmitter()
emitter.once('log', () => console.log('log once'))

// Restituisce un nuovo Array con una funzione `onceWrapper` che ha una proprietà
// `listener` che contiene il listener originale collegato sopra
const listeners = emitter.rawListeners('log')
const logFnWrapper = listeners[0]

// Registra "log once" nella console e non scollegare l'evento `once`
logFnWrapper.listener()

// Registra "log once" nella console e rimuove il listener
logFnWrapper()

emitter.on('log', () => console.log('log persistently'))
// Restituirà un nuovo Array con una singola funzione collegata da `.on()` sopra
const newListeners = emitter.rawListeners('log')

// Registra "log persistently" due volte
newListeners[0]()
emitter.emit('log')

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

[Cronologia]

VersioneModifiche
v17.4.0, v16.14.0Non più sperimentale.
v13.4.0, v12.16.0Aggiunto in: v13.4.0, v12.16.0

Il metodo Symbol.for('nodejs.rejection') viene chiamato nel caso in cui si verifichi un rifiuto di una promise quando viene emesso un evento e captureRejections è abilitato sull'emitter. È possibile utilizzare events.captureRejectionSymbol al posto di 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('il rifiuto è avvenuto per', event, 'con', err, ...args)
    this.destroy(err)
  }

  destroy(err) {
    // Demolire la risorsa qui.
  }
}
js
const { EventEmitter, captureRejectionSymbol } = require('node:events')

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

  [captureRejectionSymbol](err, event, ...args) {
    console.log('il rifiuto è avvenuto per', event, 'con', err, ...args)
    this.destroy(err)
  }

  destroy(err) {
    // Demolire la risorsa qui.
  }
}

events.defaultMaxListeners

Aggiunto in: v0.11.2

Per impostazione predefinita, è possibile registrare un massimo di 10 listener per qualsiasi singolo evento. Questo limite può essere modificato per singole istanze di EventEmitter utilizzando il metodo emitter.setMaxListeners(n). Per modificare il valore predefinito per tutte le istanze di EventEmitter, è possibile utilizzare la proprietà events.defaultMaxListeners. Se questo valore non è un numero positivo, viene generato un RangeError.

Prestare attenzione quando si imposta events.defaultMaxListeners perché la modifica interessa tutte le istanze di EventEmitter, comprese quelle create prima della modifica. Tuttavia, la chiamata a emitter.setMaxListeners(n) ha comunque la precedenza su events.defaultMaxListeners.

Questo non è un limite rigido. L'istanza di EventEmitter consentirà l'aggiunta di più listener, ma visualizzerà un avviso di traccia su stderr indicando che è stata rilevata una "possibile perdita di memoria di EventEmitter". Per qualsiasi singolo EventEmitter, i metodi emitter.getMaxListeners() e emitter.setMaxListeners() possono essere utilizzati per evitare temporaneamente questo avviso:

defaultMaxListeners non ha effetto sulle istanze di AbortSignal. Sebbene sia ancora possibile utilizzare emitter.setMaxListeners(n) per impostare un limite di avviso per le singole istanze di AbortSignal, per impostazione predefinita le istanze di AbortSignal non avviseranno.

js
import { EventEmitter } from 'node:events'
const emitter = new EventEmitter()
emitter.setMaxListeners(emitter.getMaxListeners() + 1)
emitter.once('event', () => {
  // fare cose
  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', () => {
  // fare cose
  emitter.setMaxListeners(Math.max(emitter.getMaxListeners() - 1, 0))
})

Il flag della riga di comando --trace-warnings può essere utilizzato per visualizzare la stack trace di tali avvisi.

L'avviso emesso può essere controllato con process.on('warning') e avrà le proprietà aggiuntive emitter, type e count, riferendosi rispettivamente all'istanza dell'emitter di eventi, al nome dell'evento e al numero di listener collegati. La sua proprietà name è impostata su 'MaxListenersExceededWarning'.

events.errorMonitor

Aggiunto in: v13.6.0, v12.17.0

Questo simbolo deve essere usato per installare un listener solo per monitorare gli eventi 'error'. I listener installati usando questo simbolo vengono chiamati prima che vengano chiamati i normali listener 'error'.

Installare un listener usando questo simbolo non cambia il comportamento una volta che viene emesso un evento 'error'. Pertanto, il processo si arresterà comunque se non è installato nessun listener 'error' normale.

events.getEventListeners(emitterOrTarget, eventName)

Aggiunto in: v15.2.0, v14.17.0

Restituisce una copia dell'array di listener per l'evento denominato eventName.

Per gli EventEmitter questo si comporta esattamente come chiamare .listeners sull'emettitore.

Per gli EventTarget questo è l'unico modo per ottenere i listener degli eventi per l'event target. Questo è utile per il debug e per scopi diagnostici.

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

{
  const ee = new EventEmitter()
  const listener = () => console.log('Gli eventi sono divertenti')
  ee.on('foo', listener)
  console.log(getEventListeners(ee, 'foo')) // [ [Function: listener] ]
}
{
  const et = new EventTarget()
  const listener = () => console.log('Gli eventi sono divertenti')
  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('Gli eventi sono divertenti')
  ee.on('foo', listener)
  console.log(getEventListeners(ee, 'foo')) // [ [Function: listener] ]
}
{
  const et = new EventTarget()
  const listener = () => console.log('Gli eventi sono divertenti')
  et.addEventListener('foo', listener)
  console.log(getEventListeners(et, 'foo')) // [ [Function: listener] ]
}

events.getMaxListeners(emitterOrTarget)

Aggiunto in: v19.9.0, v18.17.0

Restituisce la quantità massima di listener attualmente impostata.

Per gli EventEmitter si comporta esattamente come chiamare .getMaxListeners sull'emitter.

Per gli EventTarget questo è l'unico modo per ottenere il numero massimo di listener di eventi per l'event target. Se il numero di gestori di eventi su un singolo EventTarget supera il massimo impostato, l'EventTarget stamperà un avviso.

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])

[Cronologia]

VersioneModifiche
v15.0.0L'opzione signal ora è supportata.
v11.13.0, v10.16.0Aggiunto in: v11.13.0, v10.16.0

Crea una Promise che viene soddisfatta quando l'EventEmitter emette l'evento specificato o che viene rifiutata se l'EventEmitter emette 'error' durante l'attesa. La Promise si risolverà con un array di tutti gli argomenti emessi all'evento specificato.

Questo metodo è intenzionalmente generico e funziona con l'interfaccia EventTarget della piattaforma web, che non ha una semantica speciale per l'evento 'error' e non ascolta l'evento '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('si è verificato un errore', 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('si è verificato un errore', err)
  }
}

run()

La gestione speciale dell'evento 'error' viene utilizzata solo quando events.once() viene utilizzato per attendere un altro evento. Se events.once() viene utilizzato per attendere l'evento 'error' stesso, viene trattato come qualsiasi altro tipo di evento senza gestione speciale:

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('errore', err.message))

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

// Stampa: 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('errore', err.message))

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

// Stampa: ok boom

Un <AbortSignal> può essere utilizzato per annullare l'attesa dell'evento:

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('evento emesso!')
  } catch (error) {
    if (error.name === 'AbortError') {
      console.error("L'attesa dell'evento è stata annullata!")
    } else {
      console.error('Si è verificato un errore', error.message)
    }
  }
}

foo(ee, 'foo', ac.signal)
ac.abort() // Stampa: L'attesa dell'evento è stata annullata!
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('evento emesso!')
  } catch (error) {
    if (error.name === 'AbortError') {
      console.error("L'attesa dell'evento è stata annullata!")
    } else {
      console.error('Si è verificato un errore', error.message)
    }
  }
}

foo(ee, 'foo', ac.signal)
ac.abort() // Stampa: L'attesa dell'evento è stata annullata!

Attesa di più eventi emessi su process.nextTick()

C'è un caso limite che vale la pena notare quando si usa la funzione events.once() per attendere più eventi emessi nello stesso batch di operazioni process.nextTick(), o ogni volta che più eventi vengono emessi in modo sincrono. In particolare, poiché la coda process.nextTick() viene svuotata prima della coda di microtask Promise, e poiché EventEmitter emette tutti gli eventi in modo sincrono, è possibile che events.once() perda un evento.

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')

  // Questa Promise non si risolverà mai perché l'evento 'foo' sarà
  // già stato emesso prima che la Promise venga creata.
  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')

  // Questa Promise non si risolverà mai perché l'evento 'foo' sarà
  // già stato emesso prima che la Promise venga creata.
  await once(myEE, 'foo')
  console.log('foo')
}

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

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

Per intercettare entrambi gli eventi, crea ciascuna delle Promise prima di attenderle, quindi diventa possibile usare Promise.all(), Promise.race() o 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

[Cronologia]

VersioneModifiche
v17.4.0, v16.14.0Non più sperimentale.
v13.4.0, v12.16.0Aggiunto in: v13.4.0, v12.16.0

Valore: <boolean>

Modifica l'opzione predefinita captureRejections su tutti i nuovi oggetti EventEmitter.

events.captureRejectionSymbol

[Cronologia]

VersioneModifiche
v17.4.0, v16.14.0Non più sperimentale.
v13.4.0, v12.16.0Aggiunto in: v13.4.0, v12.16.0

Valore: Symbol.for('nodejs.rejection')

Vedi come scrivere un gestore di rifiuto personalizzato.

events.listenerCount(emitter, eventName)

Aggiunto in: v0.9.12

Deprecato a partire da: v3.2.0

[Stabile: 0 - Deprecato]

Stabile: 0 Stabilità: 0 - Deprecato: Usa invece emitter.listenerCount().

Un metodo di classe che restituisce il numero di listener per il dato eventName registrato sul dato emitter.

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

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

const myEmitter = new EventEmitter()
myEmitter.on('event', () => {})
myEmitter.on('event', () => {})
console.log(listenerCount(myEmitter, 'event'))
// Stampa: 2

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

[Cronologia]

VersioneModifiche
v22.0.0, v20.13.0Supporto per le opzioni highWaterMark e lowWaterMark, per coerenza. Le vecchie opzioni sono ancora supportate.
v20.0.0Le opzioni close, highWatermark e lowWatermark sono ora supportate.
v13.6.0, v12.16.0Aggiunto in: v13.6.0, v12.16.0
  • emitter <EventEmitter>

  • eventName <string> | <simbolo> Il nome dell'evento in ascolto

  • options <Oggetto>

    • signal <AbortSignal> Può essere utilizzato per annullare gli eventi in attesa.
    • close - <string[]> Nomi degli eventi che termineranno l'iterazione.
    • highWaterMark - <intero> Predefinito: Number.MAX_SAFE_INTEGER La soglia massima. L'emettitore viene messo in pausa ogni volta che la dimensione degli eventi in fase di buffering è superiore ad essa. Supportato solo su emettitori che implementano i metodi pause() e resume().
    • lowWaterMark - <intero> Predefinito: 1 La soglia minima. L'emettitore viene ripreso ogni volta che la dimensione degli eventi in fase di buffering è inferiore ad essa. Supportato solo su emettitori che implementano i metodi pause() e resume().
  • Restituisce: <AsyncIterator> che itera sugli eventi eventName emessi dall'emitter

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

const ee = new EventEmitter()

// Emetti più tardi
process.nextTick(() => {
  ee.emit('foo', 'bar')
  ee.emit('foo', 42)
})

for await (const event of on(ee, 'foo')) {
  // L'esecuzione di questo blocco interno è sincrona e
  // elabora un evento alla volta (anche con await). Non utilizzare
  // se è richiesta l'esecuzione simultanea.
  console.log(event) // stampa ['bar'] [42]
}
// Irraggiungibile qui
js
const { on, EventEmitter } = require('node:events')

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

  // Emetti più tardi
  process.nextTick(() => {
    ee.emit('foo', 'bar')
    ee.emit('foo', 42)
  })

  for await (const event of on(ee, 'foo')) {
    // L'esecuzione di questo blocco interno è sincrona e
    // elabora un evento alla volta (anche con await). Non utilizzare
    // se è richiesta l'esecuzione simultanea.
    console.log(event) // stampa ['bar'] [42]
  }
  // Irraggiungibile qui
})()

Restituisce un AsyncIterator che itera sugli eventi eventName. Genera un'eccezione se l'EventEmitter emette 'error'. Rimuove tutti i listener all'uscita dal ciclo. Il value restituito da ogni iterazione è un array composto dagli argomenti dell'evento emesso.

Un <AbortSignal> può essere utilizzato per annullare l'attesa degli eventi:

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

const ac = new AbortController()

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

  // Emetti più tardi
  process.nextTick(() => {
    ee.emit('foo', 'bar')
    ee.emit('foo', 42)
  })

  for await (const event of on(ee, 'foo', { signal: ac.signal })) {
    // L'esecuzione di questo blocco interno è sincrona e
    // elabora un evento alla volta (anche con await). Non utilizzare
    // se è richiesta l'esecuzione simultanea.
    console.log(event) // stampa ['bar'] [42]
  }
  // Irraggiungibile qui
})()

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

const ac = new AbortController()

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

  // Emetti più tardi
  process.nextTick(() => {
    ee.emit('foo', 'bar')
    ee.emit('foo', 42)
  })

  for await (const event of on(ee, 'foo', { signal: ac.signal })) {
    // L'esecuzione di questo blocco interno è sincrona e
    // elabora un evento alla volta (anche con await). Non utilizzare
    // se è richiesta l'esecuzione simultanea.
    console.log(event) // stampa ['bar'] [42]
  }
  // Irraggiungibile qui
})()

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

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

Aggiunto in: 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)

Aggiunto in: v20.5.0, v18.18.0

[Stabile: 1 - Sperimentale]

Stabile: 1 Stabilità: 1 - Sperimentale

Ascolta una sola volta l'evento abort sul signal fornito.

Ascoltare l'evento abort sui segnali di interruzione non è sicuro e potrebbe portare a perdite di risorse poiché un'altra terza parte con il segnale può chiamare e.stopImmediatePropagation(). Sfortunatamente, Node.js non può cambiarlo perché violerebbe lo standard web. Inoltre, l'API originale rende facile dimenticare di rimuovere i listener.

Questa API consente di utilizzare in modo sicuro AbortSignal nelle API di Node.js risolvendo questi due problemi ascoltando l'evento in modo tale che stopImmediatePropagation non impedisca l'esecuzione del listener.

Restituisce un disposable in modo che possa essere annullato più facilmente.

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

function example(signal) {
  let disposable
  try {
    signal.addEventListener('abort', e => e.stopImmediatePropagation())
    disposable = addAbortListener(signal, e => {
      // Esegui qualcosa quando il segnale viene interrotto.
    })
  } 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 => {
      // Esegui qualcosa quando il segnale viene interrotto.
    })
  } finally {
    disposable?.[Symbol.dispose]()
  }
}

Classe: events.EventEmitterAsyncResource extends EventEmitter

Aggiunto in: v17.4.0, v16.14.0

Integra EventEmitter con <AsyncResource> per EventEmitter che richiedono il tracciamento asincrono manuale. Nello specifico, tutti gli eventi emessi dalle istanze di events.EventEmitterAsyncResource verranno eseguiti all'interno del suo contesto asincrono.

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

// Gli strumenti di tracciamento asincrono lo identificheranno come 'Q'.
const ee1 = new EventEmitterAsyncResource({ name: 'Q' })

// I listener 'foo' verranno eseguiti nel contesto asincrono di EventEmitter.
ee1.on('foo', () => {
  strictEqual(executionAsyncId(), ee1.asyncId)
  strictEqual(triggerAsyncId(), ee1.triggerAsyncId)
})

const ee2 = new EventEmitter()

// I listener 'foo' su EventEmitter ordinari che non tracciano il contesto asincrono,
// tuttavia, vengono eseguiti nello stesso contesto asincrono di 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')

// Gli strumenti di tracciamento asincrono lo identificheranno come 'Q'.
const ee1 = new EventEmitterAsyncResource({ name: 'Q' })

// I listener 'foo' verranno eseguiti nel contesto asincrono di EventEmitter.
ee1.on('foo', () => {
  strictEqual(executionAsyncId(), ee1.asyncId)
  strictEqual(triggerAsyncId(), ee1.triggerAsyncId)
})

const ee2 = new EventEmitter()

// I listener 'foo' su EventEmitter ordinari che non tracciano il contesto asincrono,
// tuttavia, vengono eseguiti nello stesso contesto asincrono di emit().
ee2.on('foo', () => {
  notStrictEqual(executionAsyncId(), ee2.asyncId)
  notStrictEqual(triggerAsyncId(), ee2.triggerAsyncId)
})

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

La classe EventEmitterAsyncResource ha gli stessi metodi e accetta le stesse opzioni di EventEmitter e AsyncResource stessi.

new events.EventEmitterAsyncResource([opzioni])

  • opzioni <Object>
    • captureRejections <boolean> Abilita l'acquisizione automatica del rifiuto delle promesse](/it/api/events#capture-rejections-of-promises). Predefinito: false.
    • name <string> Il tipo di evento asincrono. Predefinito: new.target.name.
    • triggerAsyncId <number> L'ID del contesto di esecuzione che ha creato questo evento asincrono. Predefinito: executionAsyncId().
    • requireManualDestroy <boolean> Se impostato su true, disabilita emitDestroy quando l'oggetto viene sottoposto a garbage collection. Di solito non è necessario impostarlo (anche se emitDestroy viene chiamato manualmente), a meno che l'asyncId della risorsa non venga recuperato e venga chiamato l'API sensibile emitDestroy con esso. Quando è impostato su false, la chiamata emitDestroy sulla garbage collection avverrà solo se è presente almeno un hook destroy attivo. Predefinito: false.

eventemitterasyncresource.asyncId

  • Tipo: <number> L'asyncId univoco assegnato alla risorsa.

eventemitterasyncresource.asyncResource

L'oggetto AsyncResource restituito ha una proprietà aggiuntiva eventEmitter che fornisce un riferimento a questo EventEmitterAsyncResource.

eventemitterasyncresource.emitDestroy()

Chiama tutti gli hook destroy. Questo dovrebbe essere chiamato una sola volta. Verrà generato un errore se viene chiamato più di una volta. Questo deve essere chiamato manualmente. Se la risorsa viene lasciata alla garbage collection, gli hook destroy non verranno mai chiamati.

eventemitterasyncresource.triggerAsyncId

  • Tipo: <numero> Lo stesso triggerAsyncId che viene passato al costruttore AsyncResource.

API EventTarget e Event

[Cronologia]

VersioneCambiamenti
v16.0.0Gestione degli errori di EventTarget modificata.
v15.4.0Non più sperimentale.
v15.0.0Le classi EventTarget e Event sono ora disponibili come globali.
v14.5.0Aggiunto in: v14.5.0

Gli oggetti EventTarget e Event sono un'implementazione specifica di Node.js della EventTarget Web API che sono esposti da alcune API principali di Node.js.

js
const target = new EventTarget()

target.addEventListener('foo', event => {
  console.log('evento foo accaduto!')
})

EventTarget di Node.js vs. EventTarget del DOM

Ci sono due differenze fondamentali tra EventTarget di Node.js e EventTarget Web API:

NodeEventTarget vs. EventEmitter

L'oggetto NodeEventTarget implementa un sottoinsieme modificato dell'API EventEmitter che gli consente di emulare da vicino un EventEmitter in determinate situazioni. Un NodeEventTarget non è un'istanza di EventEmitter e non può essere utilizzato al posto di un EventEmitter nella maggior parte dei casi.

Listener di eventi

I listener di eventi registrati per un type di evento possono essere funzioni JavaScript o oggetti con una proprietà handleEvent il cui valore è una funzione.

In entrambi i casi, la funzione di gestione viene richiamata con l'argomento event passato alla funzione eventTarget.dispatchEvent().

Le funzioni asincrone possono essere utilizzate come listener di eventi. Se una funzione di gestione asincrona rifiuta, il rifiuto viene acquisito e gestito come descritto in gestione degli errori di EventTarget.

Un errore generato da una funzione di gestione non impedisce la chiamata degli altri gestori.

Il valore di ritorno di una funzione di gestione viene ignorato.

I gestori vengono sempre richiamati nell'ordine in cui sono stati aggiunti.

Le funzioni di gestione possono mutare l'oggetto event.

js
function handler1(event) {
  console.log(event.type) // Stampa 'foo'
  event.a = 1
}

async function handler2(event) {
  console.log(event.type) // Stampa 'foo'
  console.log(event.a) // Stampa 1
}

const handler3 = {
  handleEvent(event) {
    console.log(event.type) // Stampa 'foo'
  },
}

const handler4 = {
  async handleEvent(event) {
    console.log(event.type) // Stampa 'foo'
  },
}

const target = new EventTarget()

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

Gestione degli errori di EventTarget

Quando un listener di eventi registrato lancia un'eccezione (o restituisce una Promise che viene rifiutata), per impostazione predefinita l'errore viene trattato come un'eccezione non catturata in process.nextTick(). Ciò significa che le eccezioni non catturate in EventTarget termineranno il processo Node.js per impostazione predefinita.

Lanciare un'eccezione all'interno di un listener di eventi non impedirà l'invocazione degli altri gestori registrati.

EventTarget non implementa alcuna gestione predefinita speciale per gli eventi di tipo 'error' come EventEmitter.

Attualmente, gli errori vengono prima inoltrati all'evento process.on('error') prima di raggiungere process.on('uncaughtException'). Questo comportamento è deprecato e cambierà in una versione futura per allineare EventTarget con altre API Node.js. Qualsiasi codice che si basa sull'evento process.on('error') dovrebbe essere allineato con il nuovo comportamento.

Classe: Event

[Cronologia]

VersioneModifiche
v15.0.0La classe Event è ora disponibile tramite l'oggetto globale.
v14.5.0Aggiunto in: v14.5.0

L'oggetto Event è un adattamento della Event Web API. Le istanze vengono create internamente da Node.js.

event.bubbles

Aggiunto in: v14.5.0

Questo non viene utilizzato in Node.js ed è fornito esclusivamente per completezza.

event.cancelBubble

Aggiunto in: v14.5.0

[Stabile: 3 - Eredità]

Stabile: 3 Stabilità: 3 - Eredità: utilizzare event.stopPropagation() invece.

Alias per event.stopPropagation() se impostato su true. Questo non viene utilizzato in Node.js ed è fornito esclusivamente per completezza.

event.cancelable

Aggiunto in: v14.5.0

  • Tipo: <boolean> True se l'evento è stato creato con l'opzione cancelable.

event.composed

Aggiunto in: v14.5.0

Questo non viene utilizzato in Node.js ed è fornito solo per completezza.

event.composedPath()

Aggiunto in: v14.5.0

Restituisce un array contenente l'attuale EventTarget come unica voce o vuoto se l'evento non viene distribuito. Questo non viene utilizzato in Node.js ed è fornito solo per completezza.

event.currentTarget

Aggiunto in: v14.5.0

Alias per event.target.

event.defaultPrevented

Aggiunto in: v14.5.0

È true se cancelable è true ed è stato chiamato event.preventDefault().

event.eventPhase

Aggiunto in: v14.5.0

  • Tipo: <number> Restituisce 0 mentre un evento non viene distribuito, 2 mentre viene distribuito.

Questo non viene utilizzato in Node.js ed è fornito solo per completezza.

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

Aggiunto in: v19.5.0

[Stabile: 3 - Legacy]

Stabile: 3 Stabilità: 3 - Legacy: La specifica WHATWG lo considera obsoleto e gli utenti non dovrebbero usarlo affatto.

Ridondante con i costruttori di eventi e incapace di impostare composed. Questo non viene utilizzato in Node.js ed è fornito solo per completezza.

event.isTrusted

Aggiunto in: v14.5.0

L'evento "abort" di <AbortSignal> viene emesso con isTrusted impostato su true. Il valore è false in tutti gli altri casi.

event.preventDefault()

Aggiunto in: v14.5.0

Imposta la proprietà defaultPrevented su true se cancelable è true.

event.returnValue

Aggiunto in: v14.5.0

[Stabile: 3 - Legacy]

Stabile: 3 Stabilità: 3 - Legacy: Usa event.defaultPrevented invece.

  • Tipo: <boolean> Vero se l'evento non è stato annullato.

Il valore di event.returnValue è sempre l'opposto di event.defaultPrevented. Questo non viene utilizzato in Node.js ed è fornito puramente per completezza.

event.srcElement

Aggiunto in: v14.5.0

[Stabile: 3 - Legacy]

Stabile: 3 Stabilità: 3 - Legacy: Usa event.target invece.

Alias per event.target.

event.stopImmediatePropagation()

Aggiunto in: v14.5.0

Interrompe l'invocazione dei listener di eventi dopo che quello corrente è completo.

event.stopPropagation()

Aggiunto in: v14.5.0

Questo non viene utilizzato in Node.js ed è fornito puramente per completezza.

event.target

Aggiunto in: v14.5.0

event.timeStamp

Aggiunto in: v14.5.0

Il timestamp in millisecondi in cui l'oggetto Event è stato creato.

event.type

Aggiunto in: v14.5.0

L'identificatore del tipo di evento.

Classe: EventTarget

[Cronologia]

VersioneModifiche
v15.0.0La classe EventTarget è ora disponibile tramite l'oggetto globale.
v14.5.0Aggiunto in: v14.5.0

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

[Cronologia]

VersioneModifiche
v15.4.0aggiungi supporto per l'opzione signal.
v14.5.0Aggiunto in: v14.5.0
  • type <string>
  • listener <Function> | <EventListener>
  • options <Object>
    • once <boolean> Quando true, il listener viene rimosso automaticamente quando viene invocato la prima volta. Predefinito: false.
    • passive <boolean> Quando true, funge da suggerimento che il listener non chiamerà il metodo preventDefault() dell'oggetto Event. Predefinito: false.
    • capture <boolean> Non direttamente utilizzato da Node.js. Aggiunto per completezza dell'API. Predefinito: false.
    • signal <AbortSignal> Il listener verrà rimosso quando viene chiamato il metodo abort() dell'oggetto AbortSignal specificato.

Aggiunge un nuovo handler per l'evento type. Qualsiasi listener specificato viene aggiunto una sola volta per type e per valore dell'opzione capture.

Se l'opzione once è true, il listener viene rimosso dopo la successiva emissione di un evento type.

L'opzione capture non viene utilizzata da Node.js in alcun modo funzionale se non per tracciare i listener di eventi registrati secondo la specifica EventTarget. In particolare, l'opzione capture viene utilizzata come parte della chiave quando si registra un listener. Qualsiasi singolo listener può essere aggiunto una volta con capture = false e una volta con capture = true.

js
function handler(event) {}

const target = new EventTarget()
target.addEventListener('foo', handler, { capture: true }) // prima
target.addEventListener('foo', handler, { capture: false }) // seconda

// Rimuove la seconda istanza di handler
target.removeEventListener('foo', handler)

// Rimuove la prima istanza di handler
target.removeEventListener('foo', handler, { capture: true })

eventTarget.dispatchEvent(event)

Aggiunto in: v14.5.0

  • event <Event>
  • Restituisce: <boolean> true se il valore dell'attributo cancelable dell'evento è false o il suo metodo preventDefault() non è stato invocato, altrimenti false.

Invia l'evento all'elenco di gestori per event.type.

Gli ascoltatori di eventi registrati vengono invocati in modo sincrono nell'ordine in cui sono stati registrati.

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

Aggiunto in: v14.5.0

Rimuove il listener dall'elenco di gestori per l'evento type.

Classe: CustomEvent

[Storia]

VersioneModifiche
v23.0.0Non più sperimentale.
v22.1.0, v20.13.0CustomEvent è ora stabile.
v19.0.0Non più nascosto dietro il flag CLI --experimental-global-customevent.
v18.7.0, v16.17.0Aggiunto in: v18.7.0, v16.17.0

[Stabile: 2 - Stabile]

Stabile: 2 Stabilità: 2 - Stabile

L'oggetto CustomEvent è un adattamento della CustomEvent Web API. Le istanze vengono create internamente da Node.js.

event.detail

[Storia]

VersioneModifiche
v22.1.0, v20.13.0CustomEvent è ora stabile.
v18.7.0, v16.17.0Aggiunto in: v18.7.0, v16.17.0

[Stabile: 2 - Stabile]

Stabile: 2 Stabilità: 2 - Stabile

  • Tipo: <any> Restituisce i dati personalizzati passati durante l'inizializzazione.

Sola lettura.

Classe: NodeEventTarget

Aggiunto in: v14.5.0

NodeEventTarget è un'estensione specifica di Node.js a EventTarget che emula un sottoinsieme dell'API EventEmitter.

nodeEventTarget.addListener(type, listener)

Aggiunto in: v14.5.0

Estensione specifica di Node.js alla classe EventTarget che emula l'equivalente API EventEmitter. L'unica differenza tra addListener() e addEventListener() è che addListener() restituirà un riferimento a EventTarget.

nodeEventTarget.emit(type, arg)

Aggiunto in: v15.2.0

  • type <string>
  • arg <any>
  • Restituisce: <boolean> true se esistono listener di eventi registrati per type, altrimenti false.

Estensione specifica di Node.js alla classe EventTarget che distribuisce arg alla lista di gestori per type.

nodeEventTarget.eventNames()

Aggiunto in: v14.5.0

Estensione specifica di Node.js alla classe EventTarget che restituisce un array di nomi di type di eventi per i quali sono registrati listener di eventi.

nodeEventTarget.listenerCount(type)

Aggiunto in: v14.5.0

Estensione specifica di Node.js alla classe EventTarget che restituisce il numero di listener di eventi registrati per type.

nodeEventTarget.setMaxListeners(n)

Aggiunto in: v14.5.0

Estensione specifica di Node.js alla classe EventTarget che imposta il numero massimo di listener di eventi come n.

nodeEventTarget.getMaxListeners()

Aggiunto in: v14.5.0

Estensione specifica di Node.js alla classe EventTarget che restituisce il numero massimo di listener di eventi.

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

Aggiunto in: v14.5.0

Alias specifico di Node.js per eventTarget.removeEventListener().

nodeEventTarget.on(type, listener)

Aggiunto in: v14.5.0

Alias specifico di Node.js per eventTarget.addEventListener().

nodeEventTarget.once(type, listener)

Aggiunto in: v14.5.0

Estensione specifica di Node.js alla classe EventTarget che aggiunge un listener once per il dato evento type. Questo equivale a chiamare on con l'opzione once impostata su true.

nodeEventTarget.removeAllListeners([type])

Aggiunto in: v14.5.0

Estensione specifica di Node.js alla classe EventTarget. Se viene specificato type, rimuove tutti i listener registrati per type, altrimenti rimuove tutti i listener registrati.

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

Aggiunto in: v14.5.0

Estensione specifica di Node.js alla classe EventTarget che rimuove il listener per il type fornito. L'unica differenza tra removeListener() e removeEventListener() è che removeListener() restituirà un riferimento a EventTarget.