Ein Ereignis ist eine Benachrichtigung, die ein Ereignis aus der jüngsten Vergangenheit beschreibt.
Eine typische Implementierung eines ereignisgesteuerten Systems verwendet Event-Dispatcher- und Handler-Funktionen (oder Abonnenten ). Der Dispatcher bietet eine API, um Handler mit Ereignissen zu verbinden (jQuery bind
), und eine Methode, um ein Ereignis für seine Abonnenten zu veröffentlichen ( trigger
in jQuery). Wenn es sich um E / A- oder UI-Ereignisse handelt, gibt es normalerweise auch eine Ereignisschleife , die neue Ereignisse wie Mausklicks erkennt und an den Dispatcher weiterleitet. In JS-Land werden der Dispatcher und die Ereignisschleife vom Browser bereitgestellt.
Bei Code, der direkt mit dem Benutzer interagiert und auf Tastendruck und Klicken reagiert, ist eine ereignisgesteuerte Programmierung (oder eine Variation davon, z. B. eine funktionale reaktive Programmierung ) fast unvermeidbar. Sie, der Programmierer, haben keine Ahnung, wann oder wo der Benutzer klicken wird. Es liegt also am GUI-Framework oder Browser, die Aktion des Benutzers in seiner Ereignisschleife zu erkennen und Ihren Code zu benachrichtigen. Diese Art von Infrastruktur wird auch in Netzwerkanwendungen verwendet (siehe NodeJS).
Ihr Beispiel, in dem Sie ein Ereignis in Ihrem Code auslösen, anstatt eine Funktion direkt aufzurufen, weist einige interessantere Kompromisse auf, auf die ich weiter unten eingehen werde. Der Hauptunterschied besteht darin, dass der Herausgeber eines Ereignisses ( makeItSnow
) den Empfänger des Anrufs nicht angibt. das ist anderswo verkabelt (im aufruf zu bind
in deinem beispiel). Dies wird Feuer-und-Vergessen genannt : makeItSnow
Kündigt der Welt an, dass es schneit, aber es ist egal, wer zuhört, was als nächstes passiert oder wann es passiert - es sendet einfach die Nachricht und entstaubt seine Hände.
Der ereignisgesteuerte Ansatz entkoppelt also den Absender der Nachricht vom Empfänger. Ein Vorteil, den Sie dadurch erhalten, besteht darin, dass ein bestimmtes Ereignis mehrere Handler haben kann. Sie können eine gritRoads
Funktion an Ihr Schneeereignis binden, ohne den vorhandenen shovelSnow
Handler zu beeinträchtigen . Sie haben Flexibilität bei der Verkabelung Ihrer Anwendung. Um ein Verhalten auszuschalten, müssen Sie lediglich den bind
Anruf entfernen , anstatt den Code zu durchsuchen, um alle Instanzen des Verhaltens zu finden.
Ein weiterer Vorteil der ereignisgesteuerten Programmierung besteht darin, dass Sie sich übergreifend Gedanken machen können. Der Event-Dispatcher spielt die Rolle des Vermittlers , und einige Bibliotheken (z. B. Brighter ) verwenden eine Pipeline, damit Sie allgemeine Anforderungen wie Protokollierung oder Dienstgüte problemlos einbinden können.
Vollständige Offenlegung: Brighter wird bei Huddle entwickelt, wo ich arbeite.
Ein dritte Vorteil , dass der Absender eines Ereignis vom Empfänger entkoppelt ist , dass es gibt Ihnen Flexibilität bei , wenn Sie das Ereignis zu behandeln. Sie können jeden Ereignistyp in einem eigenen Thread verarbeiten (sofern Ihr Event-Dispatcher dies unterstützt), oder Sie können ausgelöste Ereignisse auf einen Nachrichtenbroker wie RabbitMQ übertragen und mit einem asynchronen Prozess verarbeiten oder sie sogar über Nacht in großen Mengen verarbeiten. Der Empfänger des Ereignisses kann sich in einem separaten Prozess oder auf einem separaten Computer befinden. Sie müssen den Code, der das Ereignis auslöst, nicht ändern, um dies zu tun! Dies ist die große Idee hinter "Microservice" -Architekturen: Autonome Dienste kommunizieren über Ereignisse, wobei Messaging-Middleware das Rückgrat der Anwendung ist.
Ein etwas anderes Beispiel für einen ereignisgesteuerten Stil finden Sie im domänengesteuerten Entwurf, bei dem Domänenereignisse verwendet werden, um die Aggregate voneinander zu trennen. Betrachten Sie beispielsweise einen Online-Shop, der Produkte basierend auf Ihrer Kaufhistorie empfiehlt. A Customer
muss seine Kaufhistorie aktualisieren, wenn a ShoppingCart
bezahlt wird. Das ShoppingCart
Aggregat kann das benachrichtigen, Customer
indem es ein CheckoutCompleted
Ereignis auslöst. Das Customer
würde in einer separaten Transaktion als Reaktion auf das Ereignis aktualisiert werden.
Der Hauptnachteil dieses ereignisgesteuerten Modells ist die Indirektion. Es ist jetzt schwieriger, den Code zu finden, der das Ereignis behandelt, da Sie nicht einfach mit Ihrer IDE dorthin navigieren können. Sie müssen herausfinden, wo das Ereignis in der Konfiguration gebunden ist, und hoffen, dass Sie alle Handler gefunden haben. Es gibt zu jeder Zeit mehr Dinge im Kopf zu behalten. Hier können Codestilkonventionen hilfreich sein (z. B. alle Aufrufe bind
in einer Datei zusammenfassen). Aus Gründen Ihrer Gesundheit ist es wichtig, nur einen Event-Dispatcher zu verwenden und ihn konsistent zu verwenden.
Ein weiterer Nachteil ist, dass es schwierig ist, Ereignisse umzugestalten. Wenn Sie das Format eines Ereignisses ändern müssen, müssen Sie auch alle Empfänger ändern. Dies wird noch verschlimmert, wenn sich die Abonnenten eines Ereignisses auf verschiedenen Rechnern befinden, da Sie jetzt Software-Releases synchronisieren müssen!
Unter bestimmten Umständen kann die Leistung von Belang sein. Bei der Bearbeitung einer Nachricht muss der Dispatcher:
- Suchen Sie in einer Datenstruktur nach den richtigen Handlern.
- Erstellen Sie für jeden Handler eine Nachrichtenverarbeitungspipeline. Dies kann eine Reihe von Speicherzuweisungen beinhalten.
- Rufen Sie die Handler dynamisch auf (möglicherweise mithilfe von Reflection, wenn die Sprache dies erfordert).
Dies ist sicherlich langsamer als ein regulärer Funktionsaufruf, bei dem nur ein neuer Frame auf den Stack verschoben wird. Die Flexibilität, die eine ereignisgesteuerte Architektur bietet, erleichtert jedoch das Isolieren und Optimieren von langsamem Code erheblich. Die Möglichkeit, Arbeit an einen asynchronen Prozessor zu senden, ist hier ein großer Vorteil, da Sie eine Anfrage sofort bearbeiten können, während die harte Arbeit im Hintergrund erledigt wird. Wenn Sie mit der Datenbank interagieren oder Inhalte auf dem Bildschirm zeichnen, werden die Kosten für die E / A-Verarbeitung in jedem Fall die Kosten für die Verarbeitung einer Nachricht völlig übersteigen. Es geht darum, eine vorzeitige Optimierung zu vermeiden.
Zusammenfassend lässt sich sagen, dass Events eine großartige Möglichkeit sind, lose gekoppelte Software zu erstellen, aber sie sind nicht kostenlos. Es wäre beispielsweise ein Fehler, jeden Funktionsaufruf in Ihrer Anwendung durch ein Ereignis zu ersetzen . Verwenden Sie Ereignisse, um sinnvolle architektonische Unterteilungen vorzunehmen.
$(document).bind('snow', shovelShow)
. Sie müssen es nicht in eine anonyme Funktion einschließen.