Ho passato callback o semplicemente attivato le funzioni da altre funzioni nei miei programmi per far accadere le cose una volta completate le attività. Quando qualcosa finisce, avvio direttamente la funzione:

 var ground = "clean"; function shovelSnow(){ console.log("Cleaning Snow"); ground = "clean"; } function makeItSnow(){ console.log("It"s snowing"); ground = "snowy"; shovelSnow(); }  

Ma io “ve ho letto di molte strategie diverse di programmazione, e una che capisco essere potente, ma non ho ancora praticato, è basata sugli eventi (penso che un metodo di cui ho letto fosse chiamato “pub-sub” ) :

 var ground = "clean"; function shovelSnow(){ console.log("Cleaning Snow"); ground = "clean"; } function makeItSnow(){ console.log("It"s snowing"); ground = "snowy"; $(document).trigger("snow"); } $(document).bind("snow", shovelSnow);  

Vorrei “capire i punti di forza e di debolezza oggettivi dellevento -based sulla programmazione, rispetto alla semplice chiamata di tutte le funzioni dallinterno di altre funzioni. In quali situazioni di programmazione ha senso utilizzare la programmazione basata su eventi?

Commenti

  • Per inciso, puoi semplicemente usare $(document).bind('snow', shovelShow). Non è necessario racchiuderlo in una funzione anonima.
  • Potresti anche essere interessato a conoscere la ” programmazione reattiva “, che ha molto in comune con la programmazione basata sugli eventi.

Risposta

Un evento è una notifica che descrive un evento del recente passato.

Unimplementazione tipica di un sistema guidato dagli eventi utilizza un dispatcher di eventi e funzioni di gestione (o abbonati ). Il dispatcher fornisce unAPI per collegare i gestori fino agli eventi (jQuery “s bind) e un metodo per pubblicare un evento per i suoi iscritti (trigger in jQuery). Quando parli di eventi IO o UI, di solito cè anche un loop di eventi , che rileva nuovi eventi come i clic del mouse e li passa al supervisore. In JS-land, il dispatcher e il loop di eventi sono forniti dal browser.

Per il codice che interagisce direttamente con lutente – rispondendo a pressioni di tasti e clic – programmazione guidata da eventi (o una sua variazione, come programmazione reattiva funzionale ) è quasi inevitabile. Tu, il programmatore, non hai idea di quando o dove lutente farà clic, quindi dipende dal framework della GUI o browser per rilevare lazione dellutente nel suo ciclo di eventi e notificare il tuo codice. Questo tipo di infrastruttura viene utilizzato anche nelle applicazioni di rete (cf NodeJS).

Il tuo esempio, in cui si genera un evento in yo Il nostro codice invece di chiamare direttamente una funzione ha alcuni compromessi più interessanti, di cui parlerò più avanti. La differenza principale è che leditore di un evento (makeItSnow) non specifica il destinatario della chiamata; che “è cablato altrove (nella chiamata a bind nel tuo esempio). Questo si chiama spara e dimentica : makeItSnow annuncia al mondo che sta nevicando, ma non gli importa chi sta ascoltando, cosa succede dopo o quando accade: trasmette semplicemente il messaggio e si spolvera le mani.


Quindi lapproccio guidato dagli eventi disaccoppia il mittente del messaggio dal destinatario. Un vantaggio che questo ti offre è che un determinato evento può avere più gestori. Puoi associare una funzione gritRoads al tuo evento sulla neve senza influire sul gestore shovelSnow esistente. Hai flessibilità nel modo in cui la tua applicazione è cablata; per disattivare un comportamento è sufficiente rimuovere la chiamata bind piuttosto che cercare nel codice per trovare tutte le istanze del comportamento.

Un altro vantaggio di la programmazione guidata dagli eventi è che ti dà un posto dove mettere le preoccupazioni trasversali. Il dispatcher dellevento svolge il ruolo di Mediator e alcune librerie (come Brighter ) utilizzano una pipeline in modo da poter collegare facilmente requisiti generici come la registrazione o la qualità del servizio.

Divulgazione completa: Brighter è sviluppato presso Huddle, dove lavoro.

Un terzo vantaggio del disaccoppiare il mittente di un evento dal destinatario è che ti dà flessibilità quando gestisci levento. Puoi elaborare ogni tipo di evento sul proprio thread (se il tuo dispatcher di eventi lo supporta) oppure puoi inserire eventi generati su un broker di messaggi come RabbitMQ e gestirli con un processo asincrono o addirittura elaborarli in blocco durante la notte. Il destinatario dellevento potrebbe trovarsi in un processo separato o su una macchina separata. Non è necessario modificare il codice che genera levento per farlo! Questa è la grande idea dietro le architetture “microservizi”: servizi autonomi comunicano utilizzando eventi, con il middleware di messaggistica come spina dorsale dellapplicazione.

Per un esempio piuttosto diverso di stile basato sugli eventi, guarda alla progettazione basata sul dominio, dove eventi di dominio sono usati per aiutare a mantenere separati gli aggregati. Ad esempio, considera un negozio online che consiglia prodotti in base alla cronologia degli acquisti. Un Customer deve aggiornare la sua cronologia acquisti quando viene pagato un ShoppingCart. Laggregato ShoppingCart potrebbe inviare una notifica a Customer generando un evento CheckoutCompleted; Customer verrebbe aggiornato in una transazione separata in risposta allevento.


Lo svantaggio principale di questo modello basato sugli eventi è lindirizzamento. Ora è più difficile trovare il codice che gestisce levento perché non puoi semplicemente accedervi usando il tuo IDE; devi capire dove è legato levento nella configurazione e sperare di aver trovato tutti gli handler. Ci sono più cose da tenere a mente in ogni momento. Le convenzioni sullo stile del codice possono essere daiuto in questo caso (ad esempio, mettere tutte le chiamate a bind in un file). Per il bene della tua sanità mentale, è importante usare solo un dispatcher di eventi e usarlo in modo coerente.

Un altro svantaggio è che è difficile refactoring degli eventi. Se è necessario modificare il formato di un evento, è necessario modificare anche tutti i destinatari. Ciò è esacerbato quando i sottoscrittori di un evento si trovano su macchine diverse, perché ora è necessario sincronizzare le versioni del software!

In alcune circostanze, le prestazioni possono essere un problema. Durante lelaborazione di un messaggio, il dispatcher deve:

  1. Cercare i gestori corretti in una struttura di dati.
  2. Creare una pipeline di elaborazione dei messaggi per ogni gestore. Ciò può comportare un mucchio di allocazioni di memoria.
  3. Chiama dinamicamente i gestori (possibilmente usando la reflection se il linguaggio lo richiede).

Questo è certamente più lento di una normale funzione call, che implica solo il push di un nuovo frame sullo stack. Tuttavia, la flessibilità offerta da unarchitettura basata sugli eventi rende molto più semplice isolare e ottimizzare il codice lento. Avere la possibilità di inviare il lavoro a un processore asincrono è una grande vittoria qui, in quanto ti consente di servire una richiesta immediatamente mentre il duro lavoro viene gestito in background. In ogni caso, se stai interagendo con il DB o disegnando cose sullo schermo, i costi di IO assorbiranno totalmente i costi di elaborazione di un messaggio. È un caso per evitare unottimizzazione prematura.


In sintesi, gli eventi sono un ottimo modo per creare software liberamente accoppiato, ma non sono privi di costi. Sarebbe un errore, ad esempio, sostituire ogni chiamata di funzione nella tua applicazione con un evento. Utilizza gli eventi per creare divisioni architettoniche significative.

Commenti

  • Questa risposta è uguale a 5377 ‘ s risposta che ho selezionato come corretta; ‘ modifico la mia selezione per contrassegnare questa perché è più elaborata.
  • La velocità è uno svantaggio significativo del codice basato sugli eventi? Sembra che potrebbe esserlo, ma non ‘ lo so.
  • @ raptortech97 certamente può essere. Per il codice che deve essere particolarmente veloce, probabilmente vorrai evitare di inviare eventi in un ciclo interno; fortunatamente, in tali situazioni è solitamente ben definito ciò che devi fare, quindi non ‘ hai bisogno della flessibilità extra degli eventi (o pubblicazione / sottoscrizione o osservatori, che sono meccanismi equivalenti con terminologia diversa).
  • Si noti inoltre che ci sono alcuni linguaggi (ad esempio Erlang) costruiti attorno al modello dellattore in cui tutto è messaggi (eventi). In questo caso il compilatore può decidere se implementare i messaggi / eventi come chiamate dirette di funzioni o come comunicazione.
  • Per ” prestazioni ” Penso che dobbiamo distinguere tra prestazioni a thread singolo e scalabilità. I messaggi / eventi possono essere peggiori per le prestazioni a thread singolo (ma possono essere convertiti in chiamate di funzione senza costi aggiuntivi e non essere peggiori) e per la scalabilità è ‘ superiore praticamente in ogni modo (ad esempio, potrebbe portare a enormi miglioramenti delle prestazioni sui moderni sistemi multi-CPU e futuri ” many-CPU “).

Risposta

La programmazione basata su eventi viene utilizzata quando il programma non controlla la sequenza di eventi che esegue. Invece, il flusso del programma è diretto da un processo esterno come un utente (es. GUI), un altro sistema (es. Client / server) o un altro processo (es. RPC).

Ad esempio, uno script di elaborazione batch sa cosa deve fare, quindi lo fa e basta. non è basato su eventi.

Un elaboratore di testi si trova lì e aspetta che lutente inizi a digitare.Le pressioni dei tasti sono eventi che attivano la funzionalità per aggiornare il buffer del documento interno. Il programma non può sapere cosa vuoi digitare, quindi deve essere guidato dagli eventi.

La maggior parte dei programmi GUI sono guidati dagli eventi perché sono costruiti attorno allinterazione dellutente. Tuttavia, i programmi basati su eventi non sono limitati alle GUI, che è semplicemente lesempio più familiare alla maggior parte delle persone. I server Web attendono che i client si connettano e seguono un linguaggio simile. Anche i processi in background sul tuo computer possono rispondere agli eventi. Ad esempio, uno scanner antivirus su richiesta potrebbe ricevere un evento dal sistema operativo relativo a un file appena creato o aggiornato, quindi eseguire la scansione di quel file alla ricerca di virus.

Risposta

In unapplicazione basata su eventi il concetto di Listener di eventi ti darà la possibilità di scrivere ancora di più Applicazioni Loosely Coupled .

Ad esempio, un modulo o plug-in di terze parti può eliminare un record dal database e quindi attivare receordDeleted evento e lascia il resto agli ascoltatori dellevento per fare il loro lavoro. Tutto funzionerà bene, anche se il modulo di attivazione non sa nemmeno chi sta ascoltando questo particolare evento o cosa dovrebbe accadere dopo.

Risposta

Una semplice analogia che volevo aggiungere che mi ha aiutato:

Pensa ai componenti (o agli oggetti) della tua applicazione come a un grande gruppo di amici di Facebook.

Quando uno dei tuoi amici vuole dirti qualcosa, può chiamarti direttamente o pubblicarlo sulla sua bacheca di Facebook. Quando lo pubblicano sul proprio Facebook, chiunque potrebbe vederlo e reagire, ma molte persone non lo fanno. A volte è qualcosa di importante a cui la gente probabilmente avrà bisogno di reagire, come “Stiamo avendo un bambino!” o “La band di Tal dei tali sta facendo un concerto a sorpresa al Drunkin “Clam bar!”. Nellultimo caso, probabilmente il resto degli amici dovrà reagire, soprattutto se sono interessati a quella band.

Se il tuo amico vuole mantenere un segreto tra te e loro, probabilmente loro non lo pubblicherebbero sulla loro bacheca di Facebook, ti chiamerebbero direttamente e te lo direbbero. Immagina uno scenario in cui dici a una ragazza che ti piace che vorresti incontrarla in un ristorante per un appuntamento. Invece di chiamarla direttamente e chiederle lei, lo pubblichi sulla tua bacheca di Facebook affinché tutti i tuoi amici possano vederlo. Funziona, ma se hai un ex geloso, allora potrebbe vederlo e apparire al ristorante per rovinarti la giornata.

Quando decidere se costruire o meno ascoltatori di eventi per implementare qualcosa, pensa a questa analogia. Questo componente deve mettere la sua attività là fuori perché chiunque possa vederla? O hanno bisogno di chiamare qualcuno direttamente? Le cose possono diventare complicate abbastanza facilmente, quindi è attento.

Rispondi

Questa analogia che segue potrebbe aiutarti u comprendere la programmazione I / O guidata dagli eventi tracciando un parallelo con la linea di attesa alla reception del medico.

Bloccare lI / O è come se, se sei in coda, laddetto alla reception chiede a un ragazzo di fronte a te di compilare il modulo e lei aspetta che finisca. Devi aspettare il tuo turno finché il ragazzo non finisce il suo modulo, questo è il blocco.

Se il ragazzo singolo impiega 3 minuti per riempire, il decimo ragazzo deve aspettare fino a 30 minuti. Ora, per ridurre questo decimo tempo di attesa, la soluzione sarebbe aumentare il numero di receptionist, il che è costoso. Questo è ciò che accade nei server Web tradizionali. Se richiedi le informazioni di un utente, la richiesta successiva da parte di altri utenti dovrebbe attendere fino al loperazione in corso, il recupero dal Database, è completata. Ciò aumenta il “tempo di risposta” della decima richiesta e aumenta esponenzialmente per lennesimo utente. Per evitare questo, i server web tradizionali creano thread (pari al numero crescente di receptionist) per ogni singola richiesta , cioè fondamentalmente crea una copia del server per ogni richiesta, il che è costoso per il consumo di CPU poiché ogni richiesta avrà bisogno di un thread del sistema operativo. Per aumentare lapp, dovresti lanciare molta potenza di calcolo allapp .

Guidato da eventi : laltro approccio per aumentare il “tempo di risposta” della coda è quello di scegli un approccio basato sugli eventi, in cui i ragazzi in coda riceveranno il modulo, chiesto di compilare e tornare al completamento. Quindi laddetto alla reception può sempre accettare la richiesta. Questo è esattamente ciò che javascript ha fatto sin dal suo inizio. Nel browser, javascript rispondeva a eventi di clic, scorrimento, scorrimento o recupero del database dellutente e così via. Ciò è possibile in javascript intrinsecamente, perché javascript tratta le funzioni come di prima classe oggetti e possono essere passati come parametri ad altre funzioni (chiamate callback) e possono essere richiamati al completamento di una particolare attività.Questo è esattamente ciò che fa node.js sul server.Puoi trovare ulteriori informazioni sulla programmazione guidata dagli eventi e sul blocco di i / o, nel contesto del nodo qui

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *