I en del av denne opplæringen lærte vi prinsippene bak asynkron programmering og bruk av tilbakeringinger. For å gjennomgå, tillater asynkron programmering oss å skrive kode som ikke blokkerer ved å utføre blokkeringsoppgaver senere. Tilbakeringingsfunksjoner gir en måte å synkronisere utførelsen av koden vår.
Imidlertid er nesting tilbakeringinger gjentatte ganger ikke et godt mønster å følge. Her kommer løfter til redning. Løfter har blitt brukt i en stund i JavaScript-biblioteker, men nå kan du bruke dem innfødt i koden din. Async-funksjoner forbedrer løftene ved å tillate oss å skrive oppgaver ene etter hverandre uten at vi trenger å bekymre oss for tidspunktet for deres henrettelse.
La oss ta en titt på hva et løfte er konseptuelt. Tenk på scenariet der du handler på nettet, og du kjøper et par sko. Når du sjekker ut, blir du sendt en oppsummering av kjøpet ditt.
Denne bestillingsbekreftelsen er som et løfte. Løftet er din garanti for at du vil få noe tilbake senere fra selskapet. Mens bestillingen din er ventet, stopper ikke livet ditt selvfølgelig. Du fortsetter å gjøre andre oppgaver som å surfe på internett. Hvis bestillingen din er oppfylt, vil du motta en epost med fraktinformasjonen. Det er mulig at bestillingen din blir avvist. Varen du bestilte, kan ikke være på lager, eller det kan være et problem med betalingsmåten din. I dette tilfellet vil du få en epost som forteller deg om feilen.
I kodespråket er et løfte et objekt som sikrer at vi får en fremtidig verdi for vår forespørsel om det lykkes eller mislykkes. Dette er den generelle formen for å skape og bruke et løfte:
funksjonsoppgave1 () returner nytt løfte (funksjon (løse, avvise) løse (data); avvise (feil);); oppgave1 () .then (funksjon (resultat) console.log (result);) .catch (funksjon (feil) console.log (error););
For å opprette et løfte, legger du opp et løfteobjekt og skriver din asynkron kode inne i løfteets tilbakeringingsfunksjon. Dataene du vil returnere fra løftet, blir sendt som et argument til Løse
funksjonen, og feilmeldingen din sendes inn i avvise
funksjon. Vi kjeder sammen løfter ved hjelp av deretter
metode. Dette lar oss utføre oppgavene i rekkefølge.
Hvis vi må sende resultatene av en oppgave til den neste oppgaven, returnerer vi den i deretter
metode. Vi vil kanskje knytte løfter sammen når vi er interessert i å omdanne verdier eller vi må utføre vår kode i en bestemt rekkefølge. På slutten av kjeden tar vi feilene våre. Hvis det oppstår en feil i noen av oppgavene våre, hoppes de gjenværende oppgavene over, og feilen sendes til fangstblokken.
I en del av denne opplæringen brukte vi tilbakeringinger for å åpne en fil og hente et innlegg og dets kommentarer. Dette er hva den komplette koden ser ut som å bruke løfter:
const fs = krever ('fs'); const path = krever ('path'); const postsUrl = path.join (__ dirname, 'db / posts.json'); const commentsUrl = path.join (__ dirname, 'db / comments.json'); // returnere dataene fra vår filfunksjon loadCollection (url) return new Promise (funksjon (løs, avvis) fs.readFile (url, 'utf8', funksjon (feil, data) if (error) reject feil '); else resolve (JSON.parse (data)););); // returnere et objekt med id-funksjonen getRecord (samling, id) return new Promise (funksjon (løse, avvise) const data = collection.find (funksjon (element) return element.id == id;); løse (data);); // returnere en rekke kommentarer til en innleggsfunksjon getCommentsByPost (kommentarer, postId) return comments.filter (funksjon (kommentar) return comment.postId == postId;); // initialiseringskode loadCollection (postsUrl) .then (funksjon (innlegg) return getRecord (innlegg, "001";) .then (funksjon (post) console.log (post); return loadCollection (commentsUrl); ) .then (funksjon (kommentarer) const postComments = getCommentsByPost (kommentarer, "001"); console.log (postkommentarer);) .catch (funksjon (feil) console.log (error););
Forskjellen her er at vår metode for å åpne filen er pakket inn i et løfteobjekt. Og i stedet for å nesting våre oppgaver med tilbakekallinger, er de koblet sammen med deretter
.
Som du kan se, har vi ikke eliminert behovet for tilbakeringinger. Vi bruker bare dem annerledes. Før vi nestet våre tilbakeringinger, slik at vi kunne fortsette utførelsen av koden vår i neste oppgave.
Dette minner meg om når jeg ringer kundeservice om et problem, og i stedet for agenten som løser problemet mitt, blir jeg overført til noen andre. At noen andre kan eller ikke kan løse anropet, men når det gjelder den første agenten, er det andres ansvar.
Med løfter vil vi få noe tilbake før vi går til neste oppgave. Hvis vi må bære det noe til neste fortsettelse av koden, kan vi bruke en deretter
uttalelse.
Bruk løfter, skriv et program som vil åpne en fil med brukere, få brukerens info, og åpne deretter en fil med innlegg og skriv ut alle brukerens innlegg.
Løfter er en forbedring i utformingen av vårt program, men vi kan gjøre det bedre. Det ville være veldig praktisk hvis vi kunne utføre våre oppgaver synkront slik:
oppgave 1(); Task2 (); task3 ();
Vel, vi kan med asynk / avvente mønsteret. For å gjøre dette, begynner vi med å pakke inn våre oppgaver i en async-funksjon. Denne funksjonen returnerer et løfte. Da implementerer vi feilhåndtering ved å pakke inn våre oppgaver i en prøve / fangst
uttalelse.
Hvis løftet er oppfylt, vil det fullføre alle oppgaver som var inne i vår prøve
blokkere. Hvis den blir avvist, vil å fange
blokkering vil bli utført. Legge til avvente
søkeord før en oppgave pauser programmet vårt til oppgaven er fullført.
Dette er den generelle formen for bruk av async-funksjoner:
async-funksjon initTasks () prøv const a = avvente oppgave1 (); const b = avvente oppgave2 (); const c = avvente oppgave3 (); // gjør noe med a, b og c fangst (feil) // gjør noe med feilobjektet initTasks ();
Ved hjelp av dette mønsteret kan vi omskrive hvordan vi kjører koden i filene våre.
async-funksjon getPost () prøv const posts = vent på loadCollection (postsUrl); const post = avvent getRecord (innlegg, "001"); const kommentarer = avvent loadCollection (commentsUrl); const postComments = avvent getCommentsByPost (kommentarer, post.id); console.log (post); console.log (postComments); fangst (feil) console.log (feil); getPost ();
Jeg liker å strukturere vår asynkode med en prøve / fangst
setning fordi det tydelig skiller feilhåndteringskode fra vanlig kode. Hvis noen av koden i vår prøve
blokk forårsaker en feil, den vil bli håndtert av å fange
blokkere. I tillegg kan vi legge til en endelig
blokkere som vil utføre kode uansett om oppgavene våre lykkes eller mislykkes.
Et eksempel på bruk av dette mønsteret er når vi har oppryddingskode vi må utføre. Denne koden behøver ikke nødvendigvis å være inneholdt i a endelig
blokkere. Det kan skrives etter å fange
uttalelse, og det vil utføre. Løfter har ikke dette syntaksen innebygd. Vi må kutte en annen deretter
uttalelse etter vår å fange
uttalelse for å oppnå samme effekt.
Bruk async / vent, skriv et program som vil åpne en fil med brukere, få brukerens info, og åpne en fil med innlegg og skriv ut brukerens info og alle innleggene sine.
Tilbakeringinger er ikke iboende onde. Passing funksjoner i andre funksjoner er et nyttig mønster i JavaScript. Tilbakering blir et problem når vi bruker dem til å kontrollere strømmen av vår programlogikk. Siden JavaScript er asynkront, må vi passe på hvordan vi skriver vår kode fordi oppgaver ikke nødvendigvis vil bli ferdig i den rekkefølge de ble skrevet. Det er ikke noe dårlig fordi vi ikke vil ha noen oppgave å blokkere videreføringen av programmet.
Løfter er et bedre mønster for å skrive asynkron kode. De løser ikke bare rotet av nestede tilbakeringinger, men de holder også kontroll over utfallet av en oppgave i oppgaven. Å sende kontroll til en annen oppgave, om denne oppgaven er vår egen kode eller en tredjeparts API, gjør at koden er mindre pålitelig. Til slutt, async-funksjoner tillater oss å skrive vår kode synkront, noe som er mye mer intuitivt og lettere å forstå.