Un evento è una notifica che descrive un'occorrenza del passato recente.
Un'implementazione tipica di un sistema guidato da eventi utilizza un dispatcher di eventi e funzioni di gestore (o abbonati ). Il dispatcher fornisce un'API per collegare i gestori agli eventi (jQuery bind
) e un metodo per pubblicare un evento ai suoi abbonati ( trigger
in jQuery). Quando si parla di eventi IO o UI, di solito c'è anche un ciclo di eventi , che rileva nuovi eventi come i clic del mouse e li passa al dispatcher. In JS-land, il dispatcher e il loop degli eventi sono forniti dal browser.
Per il codice che interagisce direttamente con l'utente - rispondendo a pressioni di tasti e clic - la programmazione guidata dagli eventi (o una sua variazione, come la programmazione reattiva funzionale ) è quasi inevitabile. Tu, il programmatore, non hai idea di quando o dove l'utente farà clic, quindi spetta al framework GUI o al browser rilevare l'azione dell'utente nel suo ciclo di eventi e notificare il tuo codice. Questo tipo di infrastruttura viene utilizzato anche nelle applicazioni di rete (vedi NodeJS).
Il tuo esempio, in cui si genera un evento nel codice anziché chiamare direttamente una funzione, presenta alcuni compromessi più interessanti, di cui parlerò di seguito. La differenza principale è che l'editore di un evento ( makeItSnow
) non specifica il destinatario della chiamata; che è cablato altrove (nella chiamata a bind
nel tuo esempio). Questo si chiama fuoco e dimentica : makeItSnow
annuncia al mondo che sta nevicando, ma non gli importa chi sta ascoltando, cosa succede dopo o quando succede - semplicemente trasmette il messaggio e si spolvera le mani.
Quindi l'approccio guidato dagli eventi disaccoppia il mittente del messaggio dal destinatario. Un vantaggio che ti offre è che un determinato evento può avere più gestori. È possibile associare una gritRoads
funzione all'evento neve senza influire sul shovelSnow
gestore esistente . Hai flessibilità nel modo in cui l'applicazione è cablata; per disattivare un comportamento è sufficiente rimuovere la bind
chiamata anziché cercare il codice per trovare tutte le istanze del comportamento.
Un altro vantaggio della programmazione guidata dagli eventi è che ti dà un posto dove porre preoccupazioni trasversali. Il dispatcher di eventi svolge il ruolo di Mediatore e alcune librerie (come Brighter ) utilizzano una pipeline in modo da poter collegare facilmente requisiti generici come la registrazione o la qualità del servizio.
Informativa completa: Brighter è sviluppato presso Huddle, dove lavoro.
Un terzo vantaggio di disaccoppiare il mittente di un evento dal destinatario è che ti dà flessibilità quando gestisci l'evento. È possibile elaborare ogni tipo di evento sul proprio thread (se il dispatcher di eventi lo supporta) oppure è possibile inserire eventi generati su un broker di messaggi come RabbitMQ e gestirli con un processo asincrono o persino elaborarli in blocco durante la notte. Il destinatario dell'evento potrebbe trovarsi in un processo separato o su una macchina separata. Non è necessario modificare il codice che genera l'evento per farlo! Questa è la grande idea alla base delle architetture "microservice": i servizi autonomi comunicano utilizzando gli eventi, con il middleware di messaggistica come colonna portante dell'applicazione.
Per un esempio piuttosto diverso di stile guidato dagli eventi, guarda alla progettazione guidata dal dominio, in cui gli eventi di dominio vengono utilizzati per aiutare a mantenere separati gli aggregati. Ad esempio, considera un negozio online che consiglia i prodotti in base alla cronologia degli acquisti. A Customer
deve aggiornare la cronologia degli acquisti quando ShoppingCart
viene pagata una. L' ShoppingCart
aggregato potrebbe avvisare Customer
sollevando un CheckoutCompleted
evento; il Customer
otterrebbe aggiornato in una transazione separata in risposta all'evento.
Il principale svantaggio di questo modello guidato dagli eventi è l'indirizzamento indiretto. Ora è più difficile trovare il codice che gestisce l'evento perché non puoi semplicemente navigare ad esso usando il tuo IDE; devi capire dove è legato l'evento nella configurazione e sperare di aver trovato tutti i gestori. Ci sono più cose da tenere in testa in qualsiasi momento. Le convenzioni in stile codice possono aiutare qui (ad esempio, mettendo tutte le chiamate bind
in un unico file). Per motivi di sanità mentale, è importante utilizzare solo un dispatcher di eventi e utilizzarlo in modo coerente.
Un altro svantaggio è che è difficile riformattare gli eventi. Se è necessario modificare il formato di un evento, è necessario modificare anche tutti i ricevitori. Questo è esacerbato quando gli abbonati di un evento si trovano su macchine diverse, perché ora è necessario sincronizzare le versioni del software!
In determinate circostanze, le prestazioni possono essere fonte di preoccupazione. Quando elabora un messaggio, il dispatcher deve:
- Cerca i gestori corretti in alcune strutture di dati.
- Creare una pipeline di elaborazione dei messaggi per ciascun gestore. Ciò può comportare un sacco di allocazioni di memoria.
- Chiama dinamicamente i gestori (possibilmente usando la riflessione se la lingua lo richiede).
Questo è certamente più lento di una normale chiamata di funzione, che comporta solo l'inserimento di un nuovo frame nello stack. Tuttavia, la flessibilità offerta da un'architettura guidata dagli eventi rende molto più semplice isolare e ottimizzare il codice lento. Avere la possibilità di inviare lavoro a un processore asincrono è una grande vittoria qui, in quanto ti consente di soddisfare immediatamente una richiesta mentre il duro lavoro viene gestito in background. In ogni caso, se si interagisce con il DB o si disegnano elementi sullo schermo, i costi di IO aumenteranno totalmente i costi di elaborazione di un messaggio. Si tratta di evitare l'ottimizzazione prematura.
In sintesi, gli eventi sono un ottimo modo per creare software liberamente accoppiati, ma non sono privi di costi. Sarebbe un errore, ad esempio, sostituire ogni chiamata di funzione nella tua applicazione con un evento. Usa gli eventi per creare divisioni architettoniche significative.
$(document).bind('snow', shovelShow)
. Non è necessario avvolgerlo in una funzione anonima.