Programmering

Asynkron JavaScript: Forklarede tilbagekald og løfter

Det kan være svært at håndtere asynkron kode, hvilket betyder kode, der ikke udføres med det samme som webanmodninger eller timere. JavaScript giver os to måder ud af kassen til at håndtere asynkron opførsel: tilbagekald og løfter.

Callbacks var den eneste indbyggede understøttede måde at håndtere async-kode op til 2016, da Løfte objekt blev introduceret til sproget. JavaScript-udviklere havde imidlertid implementeret lignende funktionalitet på deres egne år, før løfter ankom på scenen. Lad os se på nogle af forskellene mellem tilbagekald og løfter og se, hvordan vi håndterer koordinering af flere løfter.

Asynkrone funktioner, der bruger tilbagekald, tager en funktion som en parameter, som kaldes, når arbejdet er afsluttet. Hvis du har brugt noget lignende setTimeout i browseren har du brugt tilbagekald.

// Du kan definere dit tilbagekald separat ...

lad myCallback = () => {

console.log ('Called!');

};

setTimeout (myCallback, 3000);

// ... men det er også almindeligt at se tilbagekald defineret integreret

setTimeout (() => {

console.log ('Called!');

}, 3000);

Normalt tager den funktion, der tager et tilbagekald, det som sit sidste argument. Dette er ikke tilfældet ovenfor, så lad os lade som om der er en ny funktion kaldet vente det er ligesom setTimeout men tager de to første argumenter i modsat rækkefølge:

// Vi vil bruge vores nye funktion sådan:

waitCallback (3000, () => {

console.log ('Called!');

});

Indlejrede tilbagekald og undergangspyramiden

Callbacks fungerer fint til håndtering af asynkron kode, men de bliver vanskelige, når du begynder at skulle koordinere flere asynkrone funktioner. For eksempel, hvis vi ønskede at vente to sekunder og logge noget, så vent tre sekunder og logge noget andet, så vent fire sekunder og logge noget andet, bliver vores syntaks dybt indlejret.

// Vi vil bruge vores nye funktion sådan:

waitCallback (2000, () => {

console.log ('Første tilbagekald!');

waitCallback (3000, () => {

console.log ('Second Callback!');

waitCallback (4000, () => {

console.log ('Tredje tilbagekald!');

    });

  });

});

Dette kan virke som et trivielt eksempel (og det er det), men det er ikke ualmindeligt at foretage flere webanmodninger i træk baseret på returneringsresultaterne fra en tidligere anmodning. Hvis dit AJAX-bibliotek bruger tilbagekald, kan du se strukturen ovenfor afspille. I eksempler, der er dybere indlejrede, vil du se, hvad der kaldes undergangspyramiden, som får sit navn fra pyramideformen lavet i det indrykkede hvide rum i begyndelsen af ​​linjerne.

Som du kan se, bliver vores kode strukturelt manglende og sværere at læse, når man beskæftiger sig med asynkrone funktioner, der skal ske sekventielt. Men det bliver endnu vanskeligere. Forestil dig, hvis vi kun ville starte tre eller fire webanmodninger og udføre en opgave, efter at alle er vendt tilbage. Jeg opfordrer dig til at prøve at gøre det, hvis du ikke har kørt udfordringen før.

Lettere asynkronisering med løfter

Løfter giver en mere fleksibel API til håndtering af asynkrone opgaver. Det kræver, at funktionen skrives således, at den returnerer a Løfte objekt, som har nogle standardfunktioner til håndtering af efterfølgende adfærd og koordinering af flere løfter. Hvis vores Vent tilbagekald funktion var Løfte-baseret, ville det kun kræve et argument, som er millisekunderne at vente på. Enhver efterfølgende funktionalitet ville være lænket af løftet. Vores første eksempel ville se sådan ud:

lad myHandler = () => {

console.log ('Called!');

};

waitPromise (3000). derefter (myHandler);

I eksemplet ovenfor, VentLov (3000) returnerer a Løfte objekt, der har nogle metoder, som vi kan bruge, f.eks derefter. Hvis vi ønskede at udføre flere asynkrone funktioner efter hinanden, kunne vi undgå undergangspyramiden ved at bruge løfter. Denne kode, omskrevet for at understøtte vores nye løfte, ville se sådan ud:

// Uanset hvor mange sekventielle asynkroniseringsopgaver vi har, laver vi aldrig pyramiden.

waitPromise (2000)

. derefter (() => {

console.log ('First Callback!');

return waitPromise (3000);

  })

.then (() => {

console.log ('Second Callback!');

return waitPromise (4000);

  })

.then (() => {

console.log ('Second Callback!');

returnere venteprisen (4000);

  });

Endnu bedre, hvis vi har brug for at koordinere asynkrone opgaver, der understøtter løfter, kunne vi bruge alle, som er en statisk metode på Løfte objekt, der tager flere løfter og kombinerer dem til et. Det ser ud som:

Promise.all ([

waitPromise (2000),

vent løfte (3000),

VentLov (4000)

derefter) (() => console.log ('Alt er gjort!'));

I næste uge vil vi grave nærmere i, hvordan løfter fungerer, og hvordan man bruger dem idiomatisk. Hvis du bare lærer JavaScript, eller du er interesseret i at teste din viden, så prøv at Vent tilbagekald eller prøv at opnå det svarende til Lov. Alt med tilbagekald.

Nå som altid ud til mig på Twitter med eventuelle kommentarer eller spørgsmål.