Kuidas kirjutada JavaScripti lubadus

Mis on lubadus?

JavaScripti lubadus on objekt, mis tähistab asünkroonse toimingu lõpuleviimist või ebaõnnestumist ja sellest tulenevat väärtust.¹

Lõpp.

Nalja saan muidugi. Niisiis, mida see määratlus üldse tähendab?

Esiteks on paljud JavaScripti asjad objektid. Objekti saate luua mitmel erineval viisil. Kõige tavalisem viis on objekti sõnasõnalise süntaksiga:

const myCar = { color: 'blue', type: 'sedan', doors: '4', };

Samuti saate selle luua classja selle newmärksõnaga kiirendada .

class Car { constructor(color, type, doors) { this.color = color; this.type = type; this.doors = doors } } const myCar = new Car('blue', 'sedan', '4');

console.log(myCar);

Lubadus on lihtsalt objekt, mille loome nagu hilisem näide. Instantsime selle newmärksõnaga. Kolme parameetri asemel, mille auto tegemisel edastasime (värv, tüüp ja uksed), edastame funktsiooni, millel on kaks argumenti: resolveja reject.

Lõppkokkuvõttes räägivad lubadused meile midagi asünkroonse funktsiooni lõpuleviimisest, kust selle tagastasime - kui see toimis või mitte. Me ütleme, et funktsioon õnnestus, öeldes lubadus lahendatud ja ebaõnnestunud, öeldes, et lubadus lükati tagasi.

const myPromise = new Promise(function(resolve, reject) {});

console.log(myPromise);

const myPromise = new Promise(function(resolve, reject) { resolve(10); });

Vaadake, mitte liiga hirmutav - lihtsalt meie loodud objekt. Ja kui seda veidi laiendada:

Lisaks võime kõik, mida soovime, lahendada ja tagasi lükata. Näiteks võiksime stringi asemel edastada objekti:

return new Promise((resolve, reject) => { if(somethingSuccesfulHappened) { const successObject = { msg: 'Success', data,//...some data we got back } resolve(successObject); } else { const errorObject = { msg: 'An error occured', error, //...some error we got back } reject(errorObject); } });

Või nagu me varem nägime, ei pea me midagi läbima:

return new Promise((resolve, reject) => { if(somethingSuccesfulHappend) { resolve() } else { reject(); } });

Kuidas on lood definitsiooni asünkroonse osaga?

JavaScript on ühe keermega. See tähendab, et korraga saab käivitada ainult ühte asja. Kui suudate teed ette kujutada, võite mõelda JavaScripti kui ühe rajaga kiirteed. Teatud kood (asünkroonne kood) võib libiseda õlale, et võimaldada teisel koodil seda edastada. Kui see asünkroonne kood on tehtud, naaseb see sõiduteele.

Vahemärkusena võime lubaduse anda mis tahes funktsioonilt. See ei pea olema asünkroonne. Nagu öeldud, lubadused tagastatakse tavaliselt juhtudel, kui funktsioon, millest nad tagasi tulevad, on asünkroonne. Näiteks oleks API, millel on meetodid andmete serverisse salvestamiseks, suurepärane lubaduse tagastamise kandidaat!

Takeaway:

Lubadused annavad meile võimaluse oodata meie asünkroonse koodi valmimist, hõivata sellest mõned väärtused ja edastada need väärtused meie programmi teistele osadele.

Mul on siin artikkel, mis sukeldub sügavamalt nendesse mõistetesse: Visatud aasaks: aasade ja ajalõppude mõistmine JavaScriptis.

Kuidas lubadust kasutada?

Lubaduse kasutamist nimetatakse ka lubaduse tarbimiseks . Ülaltoodud näites tagastab meie funktsioon lubaduse objekti. See võimaldab meil kasutada oma funktsiooniga meetodite aheldamist.

Siin on näide meetodite aheldamisest, mille ma vean kihla, et olete näinud:

const a = 'Some awesome string'; const b = a.toUpperCase().replace('ST', '').toLowerCase(); console.log(b); // some awesome ring

Tuletage nüüd meelde oma (teeselda) lubadust:

const somethingWasSuccesful = true; function someAsynFunction() { return new Promise((resolve, reject){ if (somethingWasSuccesful) { resolve(); } else { reject() } }); }

Ja meie lubaduse tarbimine meetodite aheldamise abil:

someAsyncFunction .then(runAFunctionIfItResolved(withTheResolvedValue)) .catch(orARunAfunctionIfItRejected(withTheRejectedValue));

(Veel) tõeline näide.

Kujutage ette, et teil on funktsioon, mis toob kasutajad andmebaasist. Olen Codepenis kirjutanud näitefunktsiooni, mis simuleerib teie kasutatavat API-d. See pakub tulemustele juurdepääsu saamiseks kahte võimalust. Esiteks võite pakkuda tagasihelistamisfunktsiooni, kus pääsete juurde kasutajale või mis tahes veale. Või kaks, funktsioon tagastab lubaduse kasutajale juurdepääsu tõrke või vea korral.

Traditsiooniliselt pääseksime asünkroonse koodi tulemustele juurde tagasihelistuste abil.

rr someDatabaseThing(maybeAnID, function(err, result)) { //...Once we get back the thing from the database... if(err) { doSomethingWithTheError(error) } else { doSomethingWithResults(results); } }

Tagasihelistamise kasutamine on ok, kuni need on liiga pesastatud. Teisisõnu peate iga uue tulemuse korral käivitama rohkem asünkroonse koodi. See tagasihelistamismudel võib põhjustada nn tagasihelistamise põrgu.

Lubadused pakuvad meile elegantsemat ja loetavamat viisi oma programmi kulgu näha.

doSomething() .then(doSomethingElse) // and if you wouldn't mind .catch(anyErrorsPlease);

Writing our own promise: Goldilocks, the Three Bears, and a Supercomputer

Imagine you found a bowl of soup. You’d like to know the temperature of that soup before you eat it. You're out of thermometers, but luckily, you have access to a supercomputer that tells you the temperature of the bowl of soup. Unfortunately, this supercomputer can take up to 10 seconds to get the results.

Here are a couple of things to notice.

  1. We initiate a global variable called result.
  2. We simulate the duration of the network delay with Math.random() and setTimeout().
  3. We simulate a temperature with Math.random().
  4. We keep the delay and temperature values confined within a range by adding some extra “math”. The range for temp is 1 to 300; the range for delay is 1000ms to 10000ms (1s to 10 seconds).
  5. We log the delay and temperature so we have an idea of how long this function will take and the results we expect to see when it’s done.

Run the function and log the results.

getTemperature(); console.log(results); // undefined

The temperature is undefined. What happened?

The function will take a certain amount of time to run. The variable is not set until the delay is over. So while we run the function, setTimeout is asynchronous. The part of the code in setTimeout moves out of the main thread into a waiting area.

I have an article here that dives deeper into this process: Thrown For a Loop: Understanding Loops and Timeouts in JavaScript.

Since the part of our function that sets the variable result moves into a holding area until it is done, our parser is free to move onto the next line. In our case, it’s our console.log(). At this point, result is still undefined since our setTimeout is not over.

So what else could we try? We could run getTemperature() and then wait 11 seconds (since our max delay is ten seconds) and then console.log the results.

getTemperature(); setTimeout(() => { console.log(result); }, 11000); // Too Hot | Delay: 3323 | Temperature: 209 deg

This works, but the problem with this technique is, although in our example we know the maximum network delay, in a real-life example it might occasionally take longer than ten seconds. And, even if we could guarantee a maximum delay of ten seconds, if the result is ready sooner, we are wasting time.

Promises to the Rescue

We are going to refactor our getTemperature() function to return a promise. And instead of setting the result, we will reject the promise unless the result is “Just Right,” in which case we will resolve the promise. In either case, we will pass in some values to both resolve and reject.

We can now use the results of our promise we are returning (also know as consuming the promise).

getTemperature() .then(result => console.log(result)) .catch(error => console.log(error)); // Reject: Too Cold | Delay: 7880 | Temperature: 43 deg

.then will get called when our promise resolves and will return whatever information we pass into resolve.

.catch will get called when our promise rejects and will return whatever information we pass into reject.

Most likely, you’ll consume promises more than you will create them. In either case, they help make our code more elegant, readable, and efficient.

Summary

  1. Lubadused on objektid, mis sisaldavad teavet mõne asünkroonse koodi täitmise ja selle tulemusel saadud väärtuste kohta.
  2. Meie poolt antud lubaduse tagastamiseks return new Promise((resolve, reject)=> {})
  3. Lubaduse tarbimiseks kasutame .thenteavet saadud lubadusest ja .catchtagasilükatud lubadusest.
  4. Tõenäoliselt kasutate (tarbite) lubadusi rohkem kui kirjutate.

Viited

1.) //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise