Ik heb callbacks doorgegeven of gewoon de functies van een andere functie in mijn programmas geactiveerd om dingen te laten gebeuren zodra de taken zijn voltooid. Als iets klaar is, activeer ik de functie direct:
var ground = "clean"; function shovelSnow(){ console.log("Cleaning Snow"); ground = "clean"; } function makeItSnow(){ console.log("It"s snowing"); ground = "snowy"; shovelSnow(); }
Maar ik heb lees over veel verschillende programmeerstrategieën, en een waarvan ik begrijp dat die krachtig is, maar die nog niet is geoefend, is gebaseerd op gebeurtenissen (ik denk dat een methode waarover ik las “pub-sub” heette) :
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);
Ik “zou graag de objectieve sterke en zwakke punten van een evenement willen begrijpen -gebaseerd programmeren, in plaats van al uw functies aan te roepen vanuit andere functies. In welke programmeersituaties is event-based programmeren zinvol om te gebruiken?
Reacties
Answer
Een gebeurtenis is een melding die een gebeurtenis uit het recente verleden beschrijft.
Een typische implementatie van een gebeurtenisgestuurd systeem maakt gebruik van een gebeurtenisverzender en handlerfuncties (of abonnees ). De dispatcher biedt een API om handlers door te sturen naar gebeurtenissen (jQuery “s bind
), en een methode om een gebeurtenis naar zijn abonnees te publiceren (trigger
in jQuery). Als je het hebt over IO- of UI-gebeurtenissen, is er meestal ook een gebeurtenislus , die nieuwe gebeurtenissen zoals muisklikken detecteert en deze doorgeeft aan de dispatcher. JS-land, de dispatcher en de gebeurtenislus worden geleverd door de browser.
Voor code die rechtstreeks met de gebruiker communiceert – die reageert op toetsaanslagen en klikken – gebeurtenisgestuurde programmering (of een variant daarvan, zoals functioneel reactief programmeren ) is bijna onvermijdelijk. Jij, de programmeur, hebt geen idee wanneer of waar de gebruiker zal klikken, dus het ligt aan het GUI-framework of browser om de actie van de gebruiker in zijn gebeurtenislus te detecteren en uw code te melden. Dit type infrastructuur wordt ook gebruikt in netwerktoepassingen (zie NodeJS).
Uw voorbeeld, waarin u een gebeurtenis in yo ur code in plaats van een functie direct aan te roepen, heeft een aantal interessantere afwegingen, die ik hieronder zal bespreken. Het belangrijkste verschil is dat de uitgever van een evenement (makeItSnow
) de ontvanger van de oproep niet specificeert; dat is ergens anders bedraad (in de aanroep naar bind
in uw voorbeeld). Dit wordt vuur-en-vergeten genoemd: makeItSnow
kondigt aan de wereld aan dat het sneeuwt, maar het maakt niet uit wie er luistert, wat er daarna gebeurt of wanneer het gebeurt – het zendt gewoon de boodschap uit en haalt het stof van zijn handen.
Dus de gebeurtenisgestuurde benadering ontkoppelt de afzender van het bericht van de ontvanger. Een voordeel dat dit u oplevert, is dat een bepaalde gebeurtenis meerdere handlers kan hebben. U kunt een gritRoads
-functie aan uw sneeuwgebeurtenis koppelen zonder de bestaande shovelSnow
handler te beïnvloeden. U heeft flexibiliteit in de manier waarop uw applicatie is bedraad; om een gedrag uit te schakelen, hoef je alleen maar de bind
aanroep te verwijderen in plaats van door de code te zoeken om alle instanties van het gedrag te vinden.
Nog een voordeel van gebeurtenisgestuurd programmeren is dat het je een plek geeft om transversale zorgen te maken. De gebeurtenisdispatcher speelt de rol van Mediator , en sommige bibliotheken (zoals Brighter ) gebruiken een pijplijn, zodat u eenvoudig generieke vereisten zoals logboekregistratie of servicekwaliteit kunt invoegen.
Volledige openbaarmaking: Brighter is ontwikkeld bij Huddle, waar ik werk.
Een derde voordeel van het ontkoppelen van de afzender van een evenement van de ontvanger is dat het je flexibiliteit geeft in wanneer je het evenement afhandelt. U kunt elk type gebeurtenis in een eigen thread verwerken (als uw gebeurtenisverzender dit ondersteunt), of u kunt verhoogde gebeurtenissen aan een message broker toevoegen, zoals RabbitMQ en behandel ze met een asynchroon proces of verwerk ze zelfs s nachts in bulk. De ontvanger van de gebeurtenis kan zich in een apart proces of op een aparte machine bevinden. U hoeft de code die de gebeurtenis oproept niet te wijzigen om dit te doen! Dit is het grote idee achter “microservice” -architecturen: autonome services communiceren via gebeurtenissen, met messaging-middleware als de ruggengraat van de applicatie.
Voor een heel ander voorbeeld van gebeurtenisgestuurde stijl, kijk naar domeingestuurd ontwerp, waarbij domeingebeurtenissen worden gebruikt om aggregaten gescheiden te houden. Overweeg bijvoorbeeld een online winkel die producten aanbeveelt op basis van uw aankoopgeschiedenis. De aankoopgeschiedenis van een Customer
moet worden bijgewerkt wanneer er voor een ShoppingCart
wordt betaald. Het ShoppingCart
-aggregaat kan de Customer
informeren door een CheckoutCompleted
-gebeurtenis te activeren; de Customer
zou worden bijgewerkt in een afzonderlijke transactie als reactie op de gebeurtenis.
Het belangrijkste nadeel van dit gebeurtenisgestuurde model is indirectheid. Het is nu moeilijker om de code te vinden die de gebeurtenis afhandelt, omdat je er niet zomaar naartoe kunt navigeren met je IDE; je moet uitzoeken waar de gebeurtenis in de configuratie aan gebonden is en hopen dat je “alle handlers hebt gevonden. Er zijn meer dingen die je op elk moment in je hoofd moet houden.” Codestijlconventies kunnen hierbij helpen (bijvoorbeeld door alle aanroepen van bind
in één bestand te plaatsen). Omwille van uw gezond verstand is het belangrijk om slechts één event dispatcher te gebruiken en deze consequent te gebruiken.
Een ander nadeel is dat het moeilijk is om events te refactoren. Als u het formaat van een evenement moet wijzigen, moet u ook alle ontvangers wijzigen. Dit wordt verergerd wanneer de abonnees van een evenement zich op verschillende computers bevinden, omdat u nu softwareversies moet synchroniseren!
In bepaalde omstandigheden kunnen de prestaties een probleem zijn. Bij het verwerken van een bericht moet de dispatcher:
- De juiste handlers opzoeken in een gegevensstructuur.
- Een berichtverwerkingspijplijn bouwen voor elke handler. Dit kan een heleboel geheugentoewijzingen met zich meebrengen.
- Roep de handlers dynamisch aan (mogelijk met behulp van reflectie als de taal dit vereist).
Dit is zeker langzamer dan een normale functie call, waarbij alleen een nieuw frame op de stapel wordt geduwd. De flexibiliteit die een gebeurtenisgestuurde architectuur u biedt, maakt het echter veel gemakkelijker om langzame code te isoleren en te optimaliseren. De mogelijkheid hebben om werk in te dienen bij een asynchrone processor is hier een grote overwinning, omdat je hiermee onmiddellijk een verzoek kunt indienen terwijl het harde werk op de achtergrond wordt afgehandeld. In elk geval, als je interactie hebt met de database of dingen op het scherm tekent, zullen de kosten van IO de kosten voor het verwerken van een bericht volledig bederven. Het is een kwestie van vroegtijdige optimalisatie vermijden.
Samenvattend zijn evenementen een geweldige manier om losjes gekoppelde software te bouwen, maar ze zijn niet zonder kosten. Het zou bijvoorbeeld een vergissing zijn om elke functieaanroep in uw toepassing te vervangen door een gebeurtenis. Gebruik gebeurtenissen om betekenisvolle architecturale indelingen te maken.
Opmerkingen
- Dit antwoord zegt hetzelfde als 5377 ‘ s antwoord dat ik als correct heb geselecteerd; Ik ‘ m verander mijn selectie om deze te markeren omdat deze verder uitwerkt.
- Is snelheid een significant nadeel van gebeurtenisgestuurde code? Het lijkt erop dat het zo zou kunnen zijn, maar ik ‘ weet het niet helemaal.
- @ raptortech97 het kan zeker zijn. Voor code die bijzonder snel moet zijn, zou je waarschijnlijk willen voorkomen dat gebeurtenissen in een innerlijke lus worden verzonden; gelukkig is het in dergelijke situaties meestal goed gedefinieerd wat u moet doen, dus u ‘ niet de extra flexibele evenementen nodig hebben (of publiceren / abonneren of waarnemers, wat gelijkwaardige mechanismen zijn met andere terminologie).
- Merk ook op dat er enkele talen (bijv. Erlang) zijn gebouwd rond het actor-model waarin alles berichten (gebeurtenissen) zijn. In dit geval kan de compiler beslissen of de berichten / gebeurtenissen worden geïmplementeerd als directe functieaanroepen of als communicatie.
- Voor ” performance ” Ik denk dat we onderscheid moeten maken tussen single-threaded prestaties en schaalbaarheid. Berichten / gebeurtenissen kunnen slechter zijn voor single-threaded prestaties (maar kunnen worden omgezet in functieaanroepen zonder extra kosten en niet slechter), en vanwege de schaalbaarheid is het ‘ superieur in vrijwel elke manier (bv. zal waarschijnlijk resulteren in enorme prestatieverbeteringen op moderne multi-CPU en toekomstige ” veel-CPU ” systemen).
Answer
Programmering op basis van gebeurtenissen wordt gebruikt wanneer het programma de volgorde van de gebeurtenissen die het uitvoert niet controleert. In plaats daarvan wordt de programmastroom gestuurd door een extern proces, zoals een gebruiker (bijv. GUI), een ander systeem (bijv. Client / server) of een ander proces (bijv. RPC).
Bijvoorbeeld een batchverwerkingsscript weet wat het moet doen, dus het doet het gewoon. Het is niet op gebeurtenissen gebaseerd.
Een tekstverwerker zit daar en wacht tot de gebruiker begint te typen.Toetsaanslagen zijn gebeurtenissen die functionaliteit activeren om de interne documentbuffer bij te werken. Het programma kan niet weten wat u wilt typen, dus het moet gebeurtenisgestuurd zijn.
De meeste GUI-programmas zijn gebeurtenisgestuurd omdat ze zijn opgebouwd rond gebruikersinteractie. Op gebeurtenissen gebaseerde programmas zijn echter niet beperkt tot GUIs, dat is gewoon het meest bekende voorbeeld voor de meeste mensen. Webservers wachten tot clients verbinding maken en volgen een soortgelijk idioom. Achtergrondprocessen op uw computer reageren mogelijk ook op gebeurtenissen. Een virusscanner op aanvraag kan bijvoorbeeld een gebeurtenis ontvangen van het besturingssysteem met betrekking tot een nieuw gemaakt of bijgewerkt bestand, en dat bestand vervolgens scannen op virussen.
Antwoord
In een Event-gebaseerde applicatie geeft het concept van Event Listeners je de mogelijkheid om nog meer te schrijven Losjes gekoppelde -toepassingen.
Een module of plug-in van derden kan bijvoorbeeld een record uit de database verwijderen en vervolgens de receordDeleted
event en laat de rest over aan de event-luisteraars om hun werk te doen. Alles zal goed werken, ook al weet de triggermodule niet eens wie er naar deze specifieke gebeurtenis luistert of wat er daarna zou moeten gebeuren.
Antwoord
Een eenvoudige analogie die ik wilde toevoegen en die me heeft geholpen:
Beschouw de componenten (of objecten) van je applicatie als een grote groep Facebook-vrienden.
Als een van je vrienden je iets wil vertellen, kunnen ze je rechtstreeks bellen of het op hun Facebook-prikbord plaatsen. Wanneer ze het op hun Facebook plaatsen, kan iedereen het zien en erop reageren, maar veel mensen doen dat niet. Soms is het iets belangrijks dat mensen er waarschijnlijk op moeten reageren, zoals We hebben een baby! of Die-en-zo-band doet een verrassingsconcert in de Drunkin “Clam bar!”. In het laatste geval zullen de rest van de vrienden er waarschijnlijk op moeten reageren, vooral als ze geïnteresseerd zijn in die band.
Als je vriend een geheim tussen jou en hen wil bewaren, is dat waarschijnlijk zouden het niet op hun Facebook-prikbord plaatsen, maar zouden ze je rechtstreeks bellen en het je vertellen. Stel je een scenario voor waarin je een meisje vertelt dat je leuk vindt om haar te ontmoeten in een restaurant voor een date. In plaats van haar rechtstreeks te bellen en te vragen haar, je plaatst het op je Facebook-wall zodat al je vrienden het kunnen zien. Dit werkt, maar als je een jaloerse ex hebt, kan ze dat zien en in het restaurant verschijnen om je dag te verpesten.
Wanneer om te beslissen of ze event-luisteraars willen inbouwen om iets te implementeren, denk eens na over deze analogie. Moet dit onderdeel hun bedrijf daarbuiten zodat iedereen het kan zien? Of moeten ze iemand rechtstreeks bellen? Dingen kunnen vrij gemakkelijk rommelig worden, dus wees voorzichtig.
Antwoord
Deze volgende analogie kan u helpen u begrijpt gebeurtenisgestuurde I / O-programmering door een parallel te trekken met de wachtrij bij de doktersreceptie.
I / O blokkeren is zoiets als, als je in de rij staat, vraagt de receptioniste een man voor je om het formulier in te vullen en zij wacht tot hij klaar is. Je moet op je beurt wachten tot de man zijn formulier heeft voltooid, dit is blokkeren.
Als het voor een enkele man 3 minuten duurt om in te vullen, moet de 10e tot 30 minuten wachten. Om de wachttijd van deze 10e man te verkorten, zou de oplossing zijn: het verhogen van het aantal receptionisten, wat kostbaar is. Dit is wat er gebeurt in traditionele webservers. Als u om gebruikersinformatie vraagt, moet een daaropvolgend verzoek van andere gebruikers wachten tot de de huidige bewerking, ophalen uit de database, is voltooid. Dit verhoogt de ‘time-to-response’ van het 10e verzoek en neemt exponentieel toe voor de nde gebruiker. Om dit te voorkomen, maakt traditionele webservers een thread (gelijk aan een toenemend aantal receptionisten) voor elk verzoek , dat wil zeggen, het maakt in feite een kopie van de server voor elk verzoek, wat kostbaar is tussen het CPU-verbruik, aangezien elk verzoek een thread van het besturingssysteem nodig heeft. Om de app op te schalen, zou je veel rekenkracht naar de app moeten gooien .
Gebeurtenisgestuurd : De andere benadering om de “responstijd” van de wachtrij op te schalen is door ga voor een event gedreven aanpak, waarbij mannen in de wachtrij de formulier, gevraagd om in te vullen en terug te komen bij voltooiing. Daarom kan de receptioniste altijd een verzoek aannemen. Dit is precies wat javascript heeft gedaan sinds het begin. In de browser zou javascript reageren op gebruikersklikgebeurtenissen, scrollen, swipen of het ophalen van de database, enzovoort. Dit is inherent mogelijk in javascript, omdat javascript functies als eersteklas behandelt objecten en ze kunnen als parameters worden doorgegeven aan andere functies (callbacks genoemd), en kunnen worden aangeroepen na voltooiing van een bepaalde taak.Dit is precies wat node.js doet op de server.U kunt meer informatie vinden over gebeurtenisgestuurd programmeren en blokkeren van i / o, in de context van node hier
$(document).bind('snow', shovelShow)
gebruiken. Het is niet nodig om het in een anonieme functie te stoppen.