Ich habe Rückrufe übergeben oder nur die Funktionen anderer Funktionen in meinen Programmen ausgelöst, damit nach Abschluss der Aufgaben etwas passiert. Wenn etwas fertig ist, löse ich die Funktion direkt aus:

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

Aber ich habe Lesen Sie über viele verschiedene Strategien in der Programmierung, und eine, die ich als leistungsstark verstehe, aber noch nicht praktiziert habe, ist ereignisbasiert (ich glaube, eine Methode, über die ich gelesen habe, hieß „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);  

Ich möchte die objektiven Stärken und Schwächen des Ereignisses verstehen -basierte Programmierung, anstatt nur alle Ihre Funktionen aus anderen Funktionen heraus aufzurufen. In welchen Programmiersituationen ist eine ereignisbasierte Programmierung sinnvoll?

Kommentare

  • Nebenbei können Sie einfach $(document).bind('snow', shovelShow) verwenden. Sie müssen es nicht in eine anonyme Funktion einbinden.
  • Möglicherweise möchten Sie auch mehr über “ reaktive Programmierung „, was viel mit ereignisgesteuerter Programmierung zu tun hat.

Antwort

Ein Ereignis ist eine Benachrichtigung, die ein Ereignis aus der jüngeren Vergangenheit beschreibt.

Eine typische Implementierung eines ereignisgesteuerten Systems verwendet die Funktionen event dispatcher und handler (oder Abonnenten ). Der Dispatcher bietet eine API zum Verkabeln von Handlern mit Ereignissen (jQuery „s bind) und eine Methode zum Veröffentlichen eines Ereignisses für seine Abonnenten (trigger in jQuery). Wenn Sie über E / A- oder UI-Ereignisse sprechen, gibt es normalerweise auch eine Ereignisschleife , die neue Ereignisse wie Mausklicks erkennt und an den Dispatcher weiterleitet JS-land, der Dispatcher und die Ereignisschleife werden vom Browser bereitgestellt.

Für Code, der direkt mit dem Benutzer interagiert und auf Tastendrücke und Klicks reagiert – ereignisgesteuerte Programmierung (oder eine Variation davon, wie z. B. funktionale reaktive Programmierung ) ist fast unvermeidlich. Sie als Programmierer haben keine Ahnung, wann oder wo der Benutzer klicken wird, daher liegt es am GUI-Framework oder Browser, um 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 auslösen in yo Ihr Code , anstatt eine Funktion direkt aufzurufen, hat einige interessantere Kompromisse, die ich unten diskutieren werde. Der Hauptunterschied besteht darin, dass der Herausgeber eines Ereignisses (makeItSnow) den Empfänger des Anrufs nicht angibt. Das ist an anderer Stelle verkabelt (im Aufruf von bind in Ihrem Beispiel). Dies wird als Feuer und Vergessen bezeichnet: makeItSnow verkündet der Welt, 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 staubt ihre Hände ab.


Der ereignisgesteuerte Ansatz entkoppelt also den Absender der Nachricht vom Empfänger. Ein Vorteil, den Sie dadurch erhalten, ist, dass ein bestimmtes Ereignis mehrere Handler haben kann. Sie können eine gritRoads -Funktion an Ihr Schneeereignis binden, ohne den vorhandenen shovelSnow -Handler zu beeinflussen. Sie haben Flexibilität bei der Verkabelung Ihrer Anwendung. Um ein Verhalten auszuschalten, müssen Sie nur den Aufruf bind entfernen, anstatt den Code zu durchsuchen, um alle Instanzen des Verhaltens zu finden.

Ein weiterer Vorteil von Ereignisgesteuerte Programmierung bietet Ihnen die Möglichkeit, Querschnittsthemen zu stellen. Der Ereignis-Dispatcher spielt die Rolle des Mediators , und einige Bibliotheken (z. B. Brighter ) verwenden Eine Pipeline, mit der Sie allgemeine Anforderungen wie Protokollierung oder Servicequalität problemlos einbinden können.

Vollständige Offenlegung: Brighter wird bei Huddle entwickelt, wo ich arbeite.

Ein dritter Vorteil der Entkopplung des Absenders eines Ereignisses vom Empfänger besteht darin, dass Sie flexibel in sind, wenn Sie das Ereignis behandeln. Sie können jeden Ereignistyp in einem eigenen Thread verarbeiten (sofern Ihr Ereignis-Dispatcher dies unterstützt) oder ausgelöste Ereignisse in einen Nachrichtenbroker wie RabbitMQ und einfügen Behandeln Sie sie mit einem asynchronen Prozess oder verarbeiten Sie sie sogar über Nacht in großen Mengen. 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 Design, in dem Domänenereignisse werden verwendet, um Aggregate getrennt zu halten. Stellen Sie sich beispielsweise einen Online-Shop vor, der Produkte basierend auf Ihrer Kaufhistorie empfiehlt. Für eine Customer muss die Kaufhistorie aktualisiert werden, wenn eine ShoppingCart bezahlt wird. Das Aggregat ShoppingCart benachrichtigt möglicherweise das Customer durch Auslösen eines CheckoutCompleted -Ereignisses. Die Customer wird als Reaktion auf das Ereignis in einer separaten Transaktion aktualisiert.


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 immer mehr Dinge, die Sie gleichzeitig im Kopf behalten können. Hier können Konventionen im Codestil hilfreich sein (z. B. alle Aufrufe von bind in einer Datei). Aus Gründen Ihrer Gesundheit ist es wichtig, nur einen Ereignis-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 verstärkt, wenn sich die Abonnenten eines Ereignisses auf verschiedenen Computern befinden, da Sie jetzt Softwareversionen synchronisieren müssen!

Unter bestimmten Umständen kann die Leistung ein Problem darstellen. Bei der Verarbeitung einer Nachricht muss der Dispatcher:

  1. die richtigen Handler in einer Datenstruktur nachschlagen.
  2. Erstellen Sie für jeden Handler eine Nachrichtenverarbeitungspipeline. Dies kann eine Reihe von Speicherzuweisungen beinhalten.
  3. Rufen Sie die Handler dynamisch auf (möglicherweise mithilfe von Reflektion, wenn die Sprache dies erfordert).

Dies ist sicherlich langsamer als eine reguläre Funktion Aufruf, bei dem nur ein neuer Frame auf den Stapel verschoben wird. Die Flexibilität, die Ihnen 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. In jedem Fall übersteigen die Kosten für E / A die Kosten für die Verarbeitung einer Nachricht vollständig, wenn Sie mit der Datenbank interagieren oder Inhalte auf dem Bildschirm zeichnen. Dies ist ein Fall, in dem eine vorzeitige Optimierung vermieden wird.


Zusammenfassend lässt sich sagen, dass Ereignisse eine großartige Möglichkeit sind, lose gekoppelte Software zu erstellen, aber nicht ohne Kosten. Es wäre beispielsweise ein Fehler, jeden Funktionsaufruf in Ihrer Anwendung durch ein Ereignis zu ersetzen. Verwenden Sie Ereignisse, um sinnvolle architektonische Unterteilungen vorzunehmen.

Kommentare

  • Diese Antwort entspricht 5377 ‚ s Antwort, die ich als richtig ausgewählt habe; Ich ‚ ändere meine Auswahl, um diese zu markieren, da sie weiter ausgeführt wird.
  • Ist Geschwindigkeit ein wesentlicher Nachteil von ereignisgesteuertem Code? Es scheint so, als ob es sein könnte, aber ich weiß es nicht genau.
  • @ raptortech97 es kann sicher sein, dass es sein kann. Id id = „69c5e52102“> . Bei Code, der besonders schnell sein muss, möchten Sie wahrscheinlich das Senden von Ereignissen in einer inneren Schleife vermeiden. Glücklicherweise ist in solchen Situationen normalerweise genau definiert, was Sie tun müssen, sodass Sie ‚ nicht besonders flexibel von Ereignissen (oder Publish / Subscribe oder Beobachtern, die äquivalente Mechanismen sind) benötigen andere Terminologie).
  • Beachten Sie auch, dass es einige Sprachen (z. B. Erlang) gibt, die um das Akteurmodell herum aufgebaut sind und in denen alles Nachrichten (Ereignisse) sind. In diesem Fall kann der Compiler entscheiden, ob die Nachrichten / Ereignisse als direkte Funktionsaufrufe oder als Kommunikation implementiert werden sollen.
  • Für “ Leistung “ Ich denke, wir müssen zwischen Single-Threaded-Leistung und Skalierbarkeit unterscheiden. Nachrichten / Ereignisse können für die Single-Thread-Leistung schlechter sein (können jedoch ohne zusätzliche Kosten in Funktionsaufrufe umgewandelt werden und sind nicht schlechter), und für die Skalierbarkeit ist sie ‚ in praktisch allen überlegen Weg (z. B. wahrscheinlich zu massiven Leistungsverbesserungen auf modernen Multi-CPU- und zukünftigen “ Mehr-CPU “ -Systemen führen).

Antwort

Ereignisbasierte Programmierung wird verwendet, wenn das Programm die von ihm ausgeführte Ereignisfolge nicht steuert. Stattdessen wird der Programmfluss von einem externen Prozess wie einem Benutzer (z. B. einer GUI), einem anderen System (z. B. Client / Server) oder einem anderen Prozess (z. B. RPC) gesteuert.

Beispielsweise ein Stapelverarbeitungsskript weiß, was es tun muss, damit es es einfach tut. Es ist nicht ereignisbasiert.

Dort befindet sich ein Textverarbeitungsprogramm, das darauf wartet, dass der Benutzer mit der Eingabe beginnt.Tastendrücke sind Ereignisse, die Funktionen zum Aktualisieren des internen Dokumentpuffers auslösen. Das Programm kann nicht wissen, was Sie eingeben möchten, daher muss es ereignisgesteuert sein.

Die meisten GUI-Programme sind ereignisgesteuert, da sie auf Benutzerinteraktion basieren. Ereignisbasierte Programme sind jedoch nicht auf GUIs beschränkt, dies ist für die meisten Menschen einfach das bekannteste Beispiel. Webserver warten darauf, dass Clients eine Verbindung herstellen und einer ähnlichen Redewendung folgen. Hintergrundprozesse auf Ihrem Computer können auch auf Ereignisse reagieren. Beispielsweise kann ein On-Demand-Virenscanner vom Betriebssystem ein Ereignis bezüglich einer neu erstellten oder aktualisierten Datei empfangen und diese Datei dann auf Viren scannen.

Antwort

In einer ereignisbasierten Anwendung können Sie mit dem Konzept der Ereignis-Listener noch mehr schreiben Locker gekoppelte Anwendungen.

Beispielsweise kann ein Modul oder Plug-In eines Drittanbieters einen Datensatz aus der Datenbank löschen und dann die receordDeleted event und überlasse den Rest den Event-Listenern, um ihre Arbeit zu erledigen. Alles wird gut funktionieren, obwohl das Auslösemodul nicht einmal weiß, wer auf dieses bestimmte Ereignis wartet oder was als nächstes passieren soll.

Antwort

Eine einfache Analogie, die ich hinzufügen wollte, hat mir geholfen:

Stellen Sie sich die Komponenten (oder Objekte) Ihrer Anwendung als eine große Gruppe von Facebook-Freunden vor.

Wenn einer Ihrer Freunde Ihnen etwas sagen möchte, kann er Sie entweder direkt anrufen oder auf seiner Facebook-Pinnwand veröffentlichen. Wenn sie es auf Facebook veröffentlichen, kann jeder es sehen und darauf reagieren, aber Viele Leute tun es nicht. Manchmal ist es etwas Wichtiges, dass die Leute wahrscheinlich darauf reagieren müssen, wie „Wir haben ein Baby!“ oder „So-and-so-Band gibt ein Überraschungskonzert im Drunkin.“ „Muschelstange!“. Im letzten Fall muss der Rest der Freunde wahrscheinlich darauf reagieren, besonders wenn sie an dieser Band interessiert sind.

Wenn Ihr Freund ein Geheimnis zwischen Ihnen und ihnen bewahren möchte, sind sie es wahrscheinlich Sie würden es nicht auf ihrer Facebook-Pinnwand posten, sie würden Sie direkt anrufen und es Ihnen sagen. Stellen Sie sich ein Szenario vor, in dem Sie einem Mädchen sagen, dass Sie es gerne in einem Restaurant für ein Date treffen würden. Anstatt sie direkt anzurufen und zu fragen Sie posten es auf Ihrer Facebook-Pinnwand, damit alle Ihre Freunde es sehen können. Dies funktioniert, aber wenn Sie einen eifersüchtigen Ex haben, könnte sie das sehen und im Restaurant erscheinen, um Ihren Tag zu ruinieren.

Wann Überlegen Sie sich diese Analogie, ob Sie Event-Listener für die Implementierung von etwas einbauen möchten oder nicht. Muss diese Komponente ihr Geschäft für jedermann sichtbar machen? Oder müssen sie jemanden direkt anrufen? Die Dinge können ziemlich leicht chaotisch werden Vorsicht.

Antwort

Diese folgende Analogie könnte Ihnen helfen Um die ereignisgesteuerte E / A-Programmierung zu verstehen, ziehen Sie eine Parallele zur Warteschlange an der Rezeption des Arztes.

Das Blockieren von E / A ist wie wenn Sie in der Warteschlange stehen, bittet die Rezeptionistin einen Mann vor Ihnen, das Formular auszufüllen, und sie wartet, bis er fertig ist. Sie müssen warten, bis Sie an der Reihe sind, bis der Mann sein Formular beendet hat. Dies blockiert.

Wenn ein einzelner Mann 3 Minuten zum Ausfüllen benötigt, muss der 10. Mann bis 30 Minuten warten. Um diese Wartezeit von 10 Personen zu verkürzen, wäre die Lösung eine Erhöhung der Anzahl der Empfangsmitarbeiter, was kostspielig ist. Dies geschieht auf herkömmlichen Webservern. Wenn Sie Benutzerinformationen anfordern, sollte die nachfolgende Anforderung durch andere Benutzer bis zum warten Der aktuelle Vorgang, der aus der Datenbank abgerufen wird, ist abgeschlossen. Dies erhöht die „Zeit bis zur Antwort“ der 10. Anforderung und erhöht sich exponentiell für den n-ten Benutzer. Um dies zu vermeiden, erstellt herkömmliche Webserver für jede einzelne Anforderung einen Thread (entspricht einer zunehmenden Anzahl von Empfangsmitarbeitern) Im Grunde genommen wird für jede Anforderung eine Kopie des Servers erstellt, was kostspielige Zwischenzeiten des CPU-Verbrauchs darstellt, da für jede Anforderung ein Betriebssystem-Thread erforderlich ist. Um die App zu skalieren, müssten Sie viel Rechenleistung auf die App werfen .

Ereignisgesteuert : Der andere Ansatz zum Skalieren der „Antwortzeit“ der Warteschlange ist: Gehen Sie für einen ereignisgesteuerten Ansatz, bei dem der Typ in der Warteschlange überreicht wird Formular, gebeten, auszufüllen und nach dem Ausfüllen zurückzukommen. Daher kann die Rezeption immer eine Anfrage entgegennehmen. Dies ist genau das, was Javascript seit seiner Gründung getan hat. Im Browser reagierte Javascript auf Benutzerklickereignisse, Scrollen, Wischen oder Datenbankabruf usw. Dies ist in Javascript von Natur aus möglich, da Javascript Funktionen als erstklassig behandelt Objekte und sie können als Parameter an andere Funktionen übergeben werden (sogenannte Rückrufe) und können nach Abschluss einer bestimmten Aufgabe aufgerufen werden. Genau das macht node.js auf dem Server.Weitere Informationen zum ereignisgesteuerten Programmieren und Blockieren von E / A im Kontext des Knotens finden Sie hier

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.