Att hålla löften med JavaScript

JavaScript, genom sin popularitet och senaste förbättringar, blir alltmer webbprogrammerarens bästa vän. Och liksom alla bästa vänner, håller JavaScript sina löften. 

Nu kanske det låter lite konstigt, men det är sant. De flesta webbläsare stöder det som kallas Promise-objektet. Ett löfte är ganska som en funktion genom att den representerar ett stycke kod eller en uppgift som du skulle vilja exekvera någon gång i framtiden.

Här ser det ut som ett löfte.

var myPromise = nytt löfte (funktion (lösa, avvisa) // Uppgift att utföra går här.);

Du kan se här att när vi skapar ett löfte ger vi det ett enda argument, vilket är en funktion som innehåller kod som vi skulle vilja utföra vid någon tidpunkt i framtiden. Du kanske också har märkt de två argumenten i funktionen som passerat till löftet, lösa och avvisa. Dessa är också funktioner och är vårt sätt att berätta om Löfte om det har gjort vad det lovade att göra. Så här använder du dem:

var myPromise = nytt löfte (funktion (lösa, avvisa) if (true) resolve ('Hello Tuts + fans!'); else reject ('Aww, fungerade inte' '););

Detta löfte kommer självklart alltid att lösa som om uttalande kommer alltid att vara sant. Det här är bara för lärande - vi ska göra något mer realistiskt senare - men föreställ dig att du byter ut Sann med ett kodstycke som du inte var 100% säker på skulle gå till jobbet.

Nu när vi har skapat ett löfte, hur använder vi det? Tja, vi måste berätta vad de lösa och avvisa funktioner är. Vi gör det genom att använda löftet sedan metod.

myPromise.then (funktion (resultat) // Lös uppringning. console.log (result);, funktion (resultat) // Avvisa återuppringning. console.error (result););

Eftersom vårt if-uttalande alltid passerar dess Sann kolla, ovanstående kod kommer alltid logga "Hello Tuts + fans!" till konsolen. Det kommer också att göra det omedelbart. Detta beror på att koden i vår Promises konstruktör är synkron, vilket betyder att den inte väntar på någon operation att utföra. Den har all information som den behöver fortsätta och gör så snart som möjligt. 

Men löften skiner verkligen, men när det gäller asynkrona uppgifter-uppgifter där du inte vet när exakt löftet kommer att uppfyllas. Ett verkligt exempel på en asynkron uppgift är att hämta en resurs, till exempel en JSON-fil, till exempel via AJAX. Vi vet inte hur länge servern ska ta för att svara, och det kan till och med misslyckas. Låt oss lägga till några AJAX till vår lösenordskod.

var myPromise = new Promise (funktion (lösa, avvisa) // Standard AJAX-förfrågan setup och ladda. var request = new XMLHttpRequest (); // Begär en användares kommentar från vår falska blogg. request.open ('GET' http://jsonplaceholder.typicode.com/posts/1 '); // Ange funktion att ringa när resursen laddas. request.onload = function () if (request.status === 200) lösa (förfrågan. svar); annars avvisa ('Sidan laddad men statusen inte OK.';; // Ange funktion för att ringa när laddningen misslyckas. request.onerror = function () reject ('Aww, did not jobba alls. '); request.send (););

Koden här är bara standard JavaScript för att utföra en AJAX-förfrågan. Vi begär en resurs, i detta fall en JSON-fil på en angiven webbadress, och vänta på att den ska svara. Vi vet aldrig exakt när. Och vi vill uppenbarligen inte stoppa utförandet av utskrift för att vänta på det, så vad gör vi? 

Tja, vi har lyckligtvis satt den här koden inom ett löfte. Genom att uttrycka det här säger vi i grund och botten: "Hej bit kod, jag måste gå just nu men jag ringer dig senare och berättar när du ska utföra. Löfta att du ska göra det och berätta för mig när du är klar?" Och koden kommer att säga, "Ja självklart. Jag lovar." 

En viktig sak att notera i ovanstående kod är kallelsen till lösa och avvisa funktioner. Kom ihåg att det här är vårt sätt att berätta vårt löfte om att vår kod har eller inte har genomförts framgångsrikt. Annars kommer vi aldrig veta.

Med samma kod från vårt grundläggande exempel kan vi se hur vår AJAX-begäran inom löftet kommer att fungera nu.

// Berätta vårt löfte att utföra sin kod // och berätta när det är klart. myPromise.then (funktion (resultat) // Utskrifter mottagna JSON till konsolen. console.log (result);, funktion (resultat) // Prints "Aww fungerade inte" eller // "Sidladdad, men status inte OK. "console.error (result););

Jag visste att vi kunde lita på dig, mitt löfte.

Chaining Promises

Nu kan du tänka på den här tiden att löften är bara snygga återuppringningsfunktioner med en snyggare syntax. Det är sant i viss mån, men för att fortsätta med vårt AJAX-exempel, säg att du behövde göra några fler förfrågningar, varje förfrågan baserad på resultatet av det sista. Eller vad om du behövde behandla JSON först? 

Att göra detta med callbacks skulle sluta i tunga nestning av funktioner, var och en blir allt svårare att hålla reda på. Lyckligtvis kan vi i världen av löften kedja sådana funktioner tillsammans som så. Här är ett exempel där vi en gång får JSON för en användares kommentar till vår falska blogg, då vill vi se till att det är små bokstäver innan vi gör något annat med det.

myPromise .then (funktion (resultat) // När vi tar emot JSON, // gör det till ett JSON-objekt och returnerar. returnera JSON.parse (result);) .then (funktion (parsedJSON) // När json har parsed, // få e-postadressen och gör den små bokstäver. returnera parsedJSON.email.toLowerCase ();) .then (funktion (emailAddress) // När texten har gjorts små bokstäver, // skriv ut den till konsolen. console.log (emailAddress);, funktion (err) // Något i ovanstående kedja gick fel? // Skriv ut avvisa output. console.error (err););

Du kan se här att medan vårt första samtal var asynkront, är det också möjligt att kedja synkrona samtal också. Koden i varje lösa funktionen inuti sedan kommer att ringas när varje återkommer. Du märker också att det bara finns en felfunktion som anges här för hela kedjan. Genom att placera detta i slutet av kedjan som avvisa funktionen i det sista sedan, något löfte i kedjan som ringer avvisa kommer att ringa den här.

Nu när vi är lite mer övertygade med löften, låt oss skapa en annan i samband med den ovanstående. Vi skapar en som tar vår nya små bokstavsadress och kommer att låtsas att skicka ett mail till den adressen. Det här är bara ett exempel för att illustrera något asynkront. Det kan vara allt som att kontakta en server för att se om e-posten var på en vitlista eller om användaren är inloggad. Vi måste ge e-postadressen till det nya löftet, men löften accepterar inte argument. Sättet att komma runt om detta är att sätta in löftet i en funktion som gör så här:

var sendEmail = funktion (emailAddress) returnera nytt löfte (funktion (lösa, avvisa) // Låter att skicka ett mail // eller göra något annat asynkront setTimeout (funktion () lösa ('E-post skickat till' + emailAddress); , 3000);); ;

Vi använder setTimeout ring här för att helt enkelt förfalska en uppgift som tar några sekunder att köra asynkront.

Så hur använder vi vår nya löfteskapande funktion? Tja, sedan varje lösa funktion som används inom a sedan bör returnera en funktion, då kan vi använda det på samma sätt som våra synkrona uppgifter.

myPromise .then (funktion (resultat) return JSON.parse (result);) .then (funktion (parsedJSON) return parsedJSON.email.toLowerCase ();) .then (funktion (emailAddress) return sendEmail (emailAddress )) .then (funktion (resultat) // Outputs "Email skickat till [email protected]" console.log (result);, funktion (err) console.error (err););

Låt oss gå över detta flöde bara för att sammanfatta vad som händer. Vårt ursprungliga löfte mitt löfte begär en bit av JSON. När den JSON är mottagen (vi vet inte när), vänder vi JSON till ett JavaScript-objekt och returnerar det värdet. 

När det är klart tar vi e-postadressen ut ur JSON och gör den små bokstäver. Då skickar vi ett mail till den adressen, och igen vet vi inte när det kommer att slutföra, men när det gör kommer vi att utföra ett framgångsrikt meddelande till konsolen. Ingen tung häckning i sikte.

Slutsats

Jag hoppas att det här har varit en användbar introduktion till löften och har gett dig bra anledning att börja använda dem i dina JavaScript-projekt. Om du vill veta mer om Löften i större detalj, kolla in Jake Archibalds utmärkta HTML5 Rocks-artikel om detta ämne.

Lär dig JavaScript: Den fullständiga guiden

Vi har byggt en komplett guide för att hjälpa dig att lära dig JavaScript, oavsett om du precis börjat som webbutvecklare eller vill utforska mer avancerade ämnen.