Jeg har sendt tilbakeringinger eller bare utløst funksjonene fra en annen funksjon i programmene mine for å få ting til å skje når oppgavene er fullført. Når noe er ferdig, utløser jeg funksjonen direkte:

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

Men jeg har lese om mange forskjellige strategier i programmering, og en som jeg forstår er kraftig, men som ennå ikke har praktisert, er hendelsesbasert (jeg tror en metode jeg leste om ble kalt «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);  

Jeg vil forstå objektive styrker og svakheter ved hendelsen -basert programmering, vs bare å ringe alle funksjonene dine fra andre funksjoner. I hvilke programmeringssituasjoner gir begivenhetsbasert programmering mening å bruke?

Kommentarer

  • Som en side kan du bare bruke $(document).bind('snow', shovelShow). Du trenger ikke å pakke den inn i en anonym funksjon.
  • Du kan også være interessert i å lære om » reaktiv programmering «, som har mye til felles med hendelsesdrevet programmering.

Svar

En hendelse er et varsel som beskriver en hendelse fra den siste tiden.

En typisk implementering av et hendelsesdrevet system benytter en hendelsesdispenser og behandlerfunksjoner (eller abonnenter ). Ekspeditøren gir en API for å koble håndterere til hendelser (jQuery «s bind), og en metode for å publisere en hendelse til abonnentene (trigger i jQuery). Når du snakker om IO- eller UI-hendelser, er det også vanligvis en hendelsessløyfe som oppdager nye hendelser som museklikk og overfører dem til avsenderen. JS-land, senderen og hendelsessløyfen leveres av nettleseren.

For kode som samhandler direkte med brukeren – svarer på tastetrykk og klikk – hendelsesdrevet programmering (eller en variasjon derav, for eksempel funksjonell reaktiv programmering ) er nesten uunngåelig. Du, programmereren, aner ikke når eller hvor brukeren skal klikke, så det er ned til GUI-rammeverket eller nettleser for å oppdage brukerens handling i hendelsessløyfen og varsle koden din. Denne typen infrastruktur brukes også i nettverksapplikasjoner (jf. NodeJS).

Ditt eksempel, der du reiser en hendelse i yo ur-koden i stedet for å ringe en funksjon direkte har noen mer interessante avveininger, som jeg vil diskutere nedenfor. Hovedforskjellen er at utgiveren av en hendelse (makeItSnow) ikke spesifiserer mottakeren av samtalen; at «er koblet til andre steder (i samtalen til bind i eksemplet ditt). Dette kalles fyr-og-glem : makeItSnow kunngjør verden at det snør, men det bryr seg ikke hvem som lytter, hva som skjer videre, eller når det skjer – det sender ganske enkelt meldingen og støver av hendene.


Så den hendelsesdrevne tilnærmingen frakobler avsenderen av meldingen fra mottakeren. En fordel dette gir deg er at en gitt begivenhet kan ha flere behandlere. Du kan binde en gritRoads -funksjon til snøhendelsen uten å påvirke den eksisterende shovelSnow -håndtereren. Du har fleksibilitet i måten søknaden din er koblet til; for å slå av en oppførsel, trenger du bare å fjerne bind samtalen i stedet for å gå på jakt gjennom koden for å finne alle forekomster av atferden.

En annen fordel med hendelsesdrevet programmering er at det gir deg et sted å sette tverrgående bekymringer. Arrangementssenderen spiller rollen som Mediator , og noen biblioteker (som Lysere ) bruker en rørledning slik at du enkelt kan plugge inn generiske krav som logging eller servicekvalitet.

Full avsløring: Brighter er utviklet på Huddle, der jeg jobber.

En tredje fordel med å koble avsenderen av en hendelse fra mottakeren, er at den gir deg fleksibilitet i når du håndterer hendelsen. Du kan behandle hver type begivenhet på sin egen tråd (hvis hendelsesutsenderen støtter den), eller du kan legge opp hevede hendelser på en meldingsmegler som RabbitMQ og håndtere dem med en asynkron prosess eller til og med behandle dem i bulk over natten. Mottakeren av arrangementet kan være i en egen prosess eller på en egen maskin. Du trenger ikke å endre koden som løfter hendelsen for å gjøre dette! Dette er den store ideen bak «mikroservice» -arkitekturer: autonome tjenester kommuniserer ved hjelp av hendelser, med meldingsprogramvare som ryggraden i applikasjonen.

For et ganske annet eksempel på hendelsesdrevet stil, se på domenedrevet design, der domenehendelser brukes til å holde aggregater atskilt. Tenk for eksempel på en nettbutikk som anbefaler produkter basert på kjøpshistorikken din. En Customer må ha kjøpshistorikken sin oppdatert når en ShoppingCart betales for. ShoppingCart aggregatet kan varsle Customer ved å heve en CheckoutCompleted hendelse; Customer vil bli oppdatert i en egen transaksjon som svar på hendelsen.


Hovednedgangen til denne hendelsesdrevne modellen er retning. Det er nå vanskeligere å finne koden som håndterer hendelsen fordi du ikke bare kan navigere til den ved hjelp av IDE; du må finne ut hvor begivenheten er bundet i konfigurasjonen, og håpe at du har funnet alle håndtererne. Det er flere ting du kan ha i hodet ditt til enhver tid. Kodestilkonvensjoner kan hjelpe her (for eksempel å sette alle samtalene til bind i en fil). Av hensyn til sunn fornuft er det viktig å bare bruke en hendelsesutsender og å bruke den konsekvent.

En annen ulempe er at det er vanskelig å omformere hendelser. Hvis du trenger å endre formatet på en hendelse, må du også endre alle mottakerne. Dette forverres når abonnentene på et arrangement er på forskjellige maskiner, for nå må du synkronisere programvareutgivelser!

I visse tilfeller kan ytelse være et problem. Når du behandler en melding, må avsenderen:

  1. Slå opp de riktige håndtererne i en eller annen datastruktur.
  2. Bygg en pipeline for meldingsbehandling for hver behandler. Dette kan innebære en mengde minnetildelinger.
  3. Ring håndtererne dynamisk (muligens ved hjelp av refleksjon hvis språket krever det).

Dette er absolutt tregere enn en vanlig funksjon samtale, som bare innebærer å skyve en ny ramme på bunken. Fleksibiliteten som en hendelsesdrevet arkitektur gir deg, gjør det imidlertid mye lettere å isolere og optimalisere treg kode. Å ha muligheten til å sende inn arbeid til en asynkron prosessor er en stor gevinst her, da det lar deg servere en forespørsel umiddelbart mens hardt arbeid blir behandlet i bakgrunnen. I alle fall, hvis du samhandler med DB eller tegner ting på skjermen, vil kostnadene ved IO overhale kostnadene ved å behandle en melding. Det er et tilfelle av å unngå for tidlig optimalisering.


Oppsummert er hendelser en fin måte å bygge løst sammenkoblet programvare på, men de er ikke uten kostnad. Det vil for eksempel være en feil å erstatte hver funksjonsanrop i applikasjonen din med en hendelse. Bruk hendelser til å lage meningsfulle arkitektoniske inndelinger.

Kommentarer

  • Dette svaret sier det samme som 5377 ‘ s svar som jeg valgte som riktig; Jeg ‘ Jeg endrer valget mitt for å markere dette fordi det utdyper nærmere.
  • Er hastighet en betydelig ulempe med hendelsesdrevet kode? Det virker som om det kunne være, men jeg vet ikke ‘.
  • @ raptortech97 det kan det absolutt være. For kode som trenger å være spesielt rask, vil du sannsynligvis unngå å sende hendelser i en indre sløyfe. Heldigvis er det i slike situasjoner vanligvis godt definert hva du trenger å gjøre, så du trenger ikke ‘ t ekstra fleksibelt av hendelser (eller publiser / abonner eller observatører, som er like mekanismer med annen terminologi).
  • Vær også oppmerksom på at det er noen språk (f.eks. Erlang) bygget rundt skuespillermodellen der alt er meldinger (hendelser). I dette tilfellet kan kompilatoren bestemme om de skal implementere meldingene / hendelsene som direkte funksjonsanrop eller som kommunikasjon.
  • For » ytelse » Jeg tror vi trenger å skille mellom ytelse med en tråd og skalerbarhet. Meldinger / hendelser kan være verre for ytelse med en tråd (men kan konverteres til funksjonsanrop uten null tilleggskostnader og ikke være dårligere), og for skalerbarhet er det ‘ overlegen i praktisk talt alle måte (f.eks. vil sannsynligvis resultere i massive ytelsesforbedringer på moderne multi-CPU og fremtidige » mange-CPU » -systemer.

Svar

Hendelsesbasert programmering brukes når programmet ikke kontrollerer hendelsesforløpet det utfører. I stedet blir programflyten styrt av en ekstern prosess, for eksempel en bruker (f.eks. GUI), et annet system (f.eks. Klient / server) eller en annen prosess (f.eks. RPC).

For eksempel et batchbehandlingsskript vet hva den trenger å gjøre, så den gjør det bare. Det er ikke hendelsesbasert.

En tekstbehandler sitter der og venter på at brukeren skal begynne å skrive.Tastetrykk er hendelser som utløser funksjonalitet for å oppdatere den interne dokumentbufferen. Programmet kan ikke vite hva du vil skrive, så det må være hendelsesdrevet.

De fleste GUI-programmer er hendelsesdrevne fordi de er bygget rundt brukerinteraksjon. Imidlertid er hendelsesbaserte programmer ikke begrenset til GUI, det er ganske enkelt det mest kjente eksemplet for folk flest. Webservere venter på at klienter skal koble til og følge et lignende uttrykk. Bakgrunnsprosesser på datamaskinen din kan svare på hendelser også. For eksempel kan en on-demand virusscanner motta en hendelse fra operativsystemet angående en nylig opprettet eller oppdatert fil, og deretter skanne filen for virus.

Svar

I en hendelsesbasert applikasjon vil begrepet Event Listers gi deg muligheten til å skrive enda mer Loosely Coupled applikasjoner.

For eksempel kan en tredjepartsmodul eller plugin-modul slette en post fra databasen og deretter utløse receordDeleted arrangement og overlate resten til arrangementets lyttere å gjøre jobben sin. Alt vil fungere bra, selv om utløsermodulen ikke en gang vet hvem som lytter til denne spesielle hendelsen eller hva som skal skje videre.

Svar

En enkel analogi jeg ønsket å legge til som hjalp meg:

Tenk på komponentene (eller objektene) i applikasjonen din som en stor gruppe Facebook-venner.

Når en av vennene dine vil fortelle deg noe, kan de enten ringe deg direkte eller legge det ut på Facebook-veggen. Når de legger det ut på Facebook, kan noen kunne se det og reagere på det, men mange mennesker ikke. Noen ganger er det noe viktig at folk sannsynligvis vil trenge å reagere på det, som «Vi» får en baby! «eller» Så-og-så-bandet gjør en overraskelseskonsert på Drunkin «Clam bar!». I det siste tilfellet vil resten av vennene sannsynligvis trenge å reagere på det, spesielt hvis de er interessert i det bandet.

Hvis vennen din ønsker å holde en hemmelighet mellom deg og dem, vil de sannsynligvis ville ikke legge det ut på Facebook-veggen, de ville ringe deg direkte og fortelle deg. Forestill deg et scenario der du forteller en jente du liker at du vil møte henne på en restaurant for en date. I stedet for å ringe henne direkte og spørre henne, du legger det ut på Facebook-veggen din slik at alle vennene dine kan se. Dette fungerer, men hvis du har en sjalu eks, så kunne hun se det og dukke opp på restauranten for å ødelegge dagen din.

Når bestemme om det skal bygges inn lyttere for å implementere noe eller ikke, tenk på denne analogien. Må denne komponenten legge virksomheten sin der ute for at noen skal se? Eller trenger de å ringe noen direkte? Ting kan bli rotete ganske enkelt, så vær forsiktig.

Svar

Denne følgende analogien kan hjelpe deg u for å forstå hendelsesdrevet I / O-programmering ved å tegne en parallell til ventelinjen ved resepsjonen til legen.

Blokkering av I / O er som om du står i køen, ber resepsjonist en fyr foran deg om å fylle ut skjemaet, og hun venter til han er ferdig. Du må vente på din tur til fyren er ferdig med skjemaet, dette blokkerer.

Hvis en fyr tar 3 minutter å fylle ut, må den 10. fyren vente til 30 minutter. Nå for å redusere denne 10. guttenes ventetid, vil løsningen være, økende antall resepsjonister, noe som er kostbart. Dette er hva som skjer i tradisjonelle webservere. Hvis du ber om en brukerinformasjon, bør etterfølgende forespørsel fra andre brukere vente til nåværende operasjon, henting fra databasen, er fullført. Dette øker «tid til svar» for den 10. forespørselen, og den øker eksponentielt for den niende brukeren. For å unngå at tradisjonelle webservere skaper tråd (tilsvarer økende antall resepsjonister) for hver enkelt forespørsel , dvs., i utgangspunktet skaper den en kopi av serveren for hver forespørsel som er kostbar interms av CPU-forbruk siden hver forespørsel vil trenge en operativsystemtråd. For å skalere opp appen, må du kaste mye beregningskraft på appen .

Hendelsesdrevet : Den andre tilnærmingen for å skalere opp køens «responstid» er å gå for begivenhetsdrevet tilnærming, der fyren i køen vil bli overlevert skjema, bedt om å fylle ut og komme tilbake etter ferdigstillelse. Derfor kan resepsjonist alltid ta forespørsel. Dette er nøyaktig hva javascript har gjort siden det ble startet. I nettleseren vil javascript svare på brukerens klikkhendelse, bla, sveipe eller hente databasen og så videre. Dette er mulig i javascript iboende, fordi javascript behandler funksjoner som første klasse objekter, og de kan sendes som parametere til andre funksjoner (kalt tilbakeringing), og kan kalles når en bestemt oppgave er fullført. Dette er hva node.js gjør på serveren.Du finner mer info om hendelsesdrevet programmering og blokkering av i / o, i sammenheng med node her

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *