När vi först börjar programmera lär vi oss att ett block av kod körs från början till botten. Detta är synkron programmering: varje operation är klar före nästa början. Det här är bra när du gör massor av saker som nästan inte tar tid för en dator att slutföra, till exempel att lägga till tal, manipulera en sträng eller tilldela variabler.
Vad händer när du vill göra något som tar relativt lång tid, till exempel att komma åt en fil på disken, skicka en nätverksförfrågan eller vänta på att en timer ska gå? I synkron programmering kan ditt skript inte göra något annat medan det väntar.
Det här kan vara bra för något enkelt eller i en situation där du har flera instanser av ditt skript som körs, men för många serverns applikationer är det en mardröm.
Ange asynkron programmering. I ett asynkront skript fortsätter din kod att utföras medan du väntar på att något ska hända, men kan hoppa tillbaka när något har hänt.
Ta till exempel en nätverksförfrågan. Om du gör en nätverksförfrågan till en långsam server som tar full tre sekunder att svara, kan ditt skript aktivt göra andra saker medan den långsamma servern svarar. I det här fallet kanske tre sekunder inte verkar vara så mycket för en människa, men en server kan svara på tusentals andra förfrågningar medan man väntar. Så, hur hanterar du asynkron i Node.js?
Det mest grundläggande sättet är genom en återuppringning. En återuppringning är bara en funktion som kallas när en asynkron operation är klar. Enligt konventionen har Node.js återuppringningsfunktioner minst ett argument, fela
. Återuppringningar kan ha fler argument (som vanligtvis representerar de data som returneras till återuppringningen), men den första kommer att vara fela
. Som du kanske har gissat, fela
har ett felobjekt (om ett fel har utlösts mer på det senare).
Låt oss ta en titt på ett mycket enkelt exempel. Vi använder Node.js inbyggda filsystemmodul (fs
). I det här skriptet läser vi innehållet i en textfil. Den sista raden i filen är a console.log
Det ställer en fråga: Om du kör det här skriptet tror du att du kommer se loggen innan vi ser innehållet i textfilen?
var fs = kräver ('fs'); fs.readFile ('a-text-file.txt', // filnamnet för en textfil som säger "Hej!" 'utf8', // kodningen av filen, i detta fall utf-8-funktionen (fel , text) // återuppringningskonsolen.log ("Fel:", fel); // Fel, om någon console.log ('Text:', text); // innehållet i filen); // Kommer det att vara före eller efter felet / texten? console.log ('Blir det här loggat före eller efter innehållet i textfilen?');
Eftersom detta är asynkron ser vi faktiskt den sista console.log
innan innehållet i textfilen. Om du har en fil som heter a-text-file.txt i samma katalog där du exekverar ditt nodskript kommer du att se det fela
är null
, och värdet av text
är befolket med innehållet i textfilen.
Om du inte har en fil som heter a-text-file.txt, fela
kommer att returnera ett felobjekt och värdet av text
kommer vara odefinierad
. Detta leder till en viktig aspekt av callbacks: du måste alltid hantera dina fel. För att hantera fel måste du kontrollera ett värde i fela
variabel; Om ett värde är närvarande, inträffade ett fel. Konventionellt, fela
Argument återkommer oftast inte falsk
, så du kan bara kontrollera för truthiness.
var fs = kräver ('fs'); fs.readFile ('a-text-file.txt', // filnamnet för en textfil som säger "Hej!" 'utf8', // kodningen av filen, i detta fall utf-8-funktionen (fel , text) // återuppringningen om (err) console.error (err); // visar ett fel på konsolen annat console.log ('Text:', text); // inget fel, så visas innehållet i filen);
Låt oss nu säga att du vill visa innehållet i två filer i en viss ordning. Du kommer att sluta med något så här:
var fs = kräver ('fs'); fs.readFile ('a-text-file.txt', // filnamnet för en textfil som säger "Hej!" 'utf8', // kodningen av filen, i detta fall utf-8-funktionen (fel , text) // återuppringningen om (err) console.error (err); // visar ett fel på konsolen annat console.log ("första textfilen:", text); // inget fel, så visa innehållet i filen fs.readFile ('another-text-file.txt', // filnamnet för en textfil som säger "Hej!" 'utf8', // kodningen av filen, i det här fallet , utf-8 funktion (fel, text) // återuppringningen om (err) console.error (err); // visa ett fel på konsolen annars console.log ("andra textfilen" ); // inget fel, så visa innehållet i filen););
Koden ser ganska otäck ut och har ett antal problem:
Du laddar filerna i följd det skulle vara effektivare om du kan ladda dem båda samtidigt och returnera värdena när båda har laddats helt.
Synaktiskt är det korrekt men svårt att läsa. Observera antalet nestade funktioner och de ökande flikarna. Du kan göra några knep så att det ser lite bättre ut, men du kan offra läsbarhet på andra sätt.
Det är inte mycket allmänt ändamål. Det fungerar bra för två filer, men om du hade nio filer ibland och andra gånger 22 eller bara en? Det sätt som det skrivs för närvarande är väldigt styvt.
Oroa dig inte, vi kan lösa alla dessa problem (och mer) med async.js.
Låt oss börja med att installera async.js-modulen.
npm installera async -save
Async.js kan användas för att limma samman arrays av funktioner i serier eller paralleller. Låt oss skriva om vårt exempel:
var async = kräver ('async'), //async.js modul fs = kräver ('fs'); (//) text-file.txt ',' utf8 ', cb);, funktion (cb) fs.readFile (' another-text-file.txt ',' utf8 ', cb);], funktion ) // Den "färdiga" återuppringningen som körs efter att funktionerna i matrisen har slutförts om (err) // Om det uppstod några fel när funktioner i arrayen kördes, skickas de som felkonsol.error (felmeddelande) err); else // Om fel är falsk är allt bra console.log ('Första textfil:', värden [0]); console.log ('Andra textfil:', värden [1]); );
Detta fungerar nästan som det föregående exemplet, i följd laddning av varje fil, och skiljer sig endast genom att den läser varje fil och visar inte resultatet tills det är klart. Koden är mer koncis och renare än föregående exempel (och vi kommer att göra det ännu bättre senare). async.series
tar en rad funktioner och kör dem efter varandra.
Varje funktion bör bara ha ett enda argument, återuppringningen (eller cb
i vår kod). cb
ska utföras med samma typ av argument som någon annan återuppringning, så vi kan uttrycka det rätt in i vårt fs.readFile
argument.
Slutligen skickas resultaten till den sista återkallelsen, det andra argumentet i till async.series
. Resultaten lagras i en array med de värden som hör samman med ordningen för funktionerna i det första argumentet för async.series
.
Med async.js förenklas felhanteringen, eftersom om den stöter på ett fel returnerar det felet till argumentet för den slutliga återuppringningen och kommer inte att utföra ytterligare asynkrona funktioner.
En relaterad funktion är async.parallel
; Det har samma argument som async.series
så du kan byta mellan de två utan att ändra resten av din syntax. Detta är en bra punkt att täcka parallellt mot samtidiga.
JavaScript är i grunden ett enkelgängat språk, vilket betyder att det bara kan göra en sak i taget. Det kan göra vissa uppgifter i en separat tråd (de flesta I / O-funktioner, till exempel), och här kommer asynkron programmering till spel med JS. Förväxla inte parallellt med samtidighet.
När du utför två saker med async.parallel
, du får inte öppna en annan tråd för att analysera JavaScript eller göra två saker åt gången - du kontrollerar verkligen när den passerar mellan funktioner i det första argumentet om async.parallel
. Så du får inte något genom att bara sätta synkron kod i async.parallel.
Detta förklaras bäst visuellt:
Här är vårt tidigare exempel skrivet för att vara parallell-den enda skillnaden är att vi använder async.parallel
hellre än async.series
.
var async = kräver ('async'), //async.js modul fs = kräver ('fs'); async.parallel (// exekvera funktionerna i det första argumentet, men vänta inte på den första funktionen för att avsluta för att starta den andra [// Det första argumentet är en uppsättning funktionerfunktioner (cb) // 'cb' är stenografi för "callback" fs.readFile ('a-text-file.txt', 'utf8', cb);, funktion (cb) fs.readFile ('another-text-file.txt', 'utf8 ', cb);], funktion (fel, värden) // Den "färdiga" återuppringningen som springer efter att funktionerna i matrisen har slutförts om (err) // Om det uppstod några fel när funktioner i arrayen kördes , kommer de att skickas som err. console.error (err); else // Om fel är falsk är allt bra console.log ('Första textfil:', värden [0]); console.log "Andra textfilen:", värden [1]););
Våra tidigare exempel har genomfört ett fast antal operationer, men vad händer om du behöver ett varierande antal asynkrona operationer? Detta blir raserigt snabbt om du bara lita på callbacks och regelbunden språkkonstruktion, förlita sig på klumpiga räknare eller tillståndskontroller som döljer den riktiga meningen med din kod. Låt oss ta en titt på den grova ekvivalenten av en för loop med async.js.
I det här exemplet skriver vi tio filer till den aktuella katalogen med sekventiella filnamn och lite kort innehåll. Du kan ändra antalet genom att ändra värdet på det första argumentet för async.times
. I det här exemplet är återuppringningen för fs.writeFile
skapar bara en fela
argument, men async.times
funktionen kan också stödja ett returvärde. Liksom async.series, skickas den till den färdiga återuppringningen i det andra argumentet som en array.
var async = kräver ('async'), fs = kräver ('fs'); async.times (10, // antal gånger för att köra funktionsfunktionen (runCount, callback) fs.writeFile ('file -' + runCount + '. txt', // det nya filnamnet 'Detta är filnummer' + runCount, // innehållet i den nya filåterkallelsen);, funktion (err) om (err) console.error (err); else console.log ('Skannade filer.';;);
Det är en bra tid att säga att de flesta async.js-funktioner, som standard, kör parallellt snarare än serier. Så i det ovanstående exemplet kommer det att börja skapa filerna och rapportera när alla är helt skapade och skrivna.
De funktioner som parallellt kör parallellt har en följdseriefunktion som indikeras av funktionen som slutar med, du gissade den, "Serie". Så om du vill köra detta exempel i serie snarare än parallellt, skulle du ändra async.times
till async.timesSeries
.
För vårt nästa exempel på looping, tar vi en titt på funktionen async.until. async.until
exekverar en asynkron funktion (i serie) tills ett visst villkor är uppfyllt. Den här funktionen har tre funktioner som argument.
Den första funktionen är testet där du returnerar antingen sant (om du vill stoppa slingan) eller false (om du vill fortsätta slingan). Det andra argumentet är den asynkrona funktionen, och den slutliga är den färdiga återuppringningen. Ta en titt på detta exempel:
var async = kräver ('async'), fs = kräver ('fs'), startTime = ny Datum (). getTime (), // Unix tidsstämpel i millisekunder runCount = 0; async.until (function () // return true om 4 millisekunder har förflutit, annars falskt (och fortsätt att köra skriptet) returnera nytt datum (). getTime ()> (startTime + 5);, funktion (återuppringning) runCount + = 1; fs.writeFile ('timed-fil -' + runCount + '. txt', // det nya filnamnet 'Detta är filnummer' + runCount, // innehållet i den nya filåterkallelsen); funktion (err) om (err) console.error (err); else console.log ('Skannade filer.'););
Detta skript skapar nya textfiler i fem millisekunder. I början av manuset får vi starttiden i millisekundens unix-epok, och sedan i testfunktionen får vi den aktuella tiden och testet för att se om det är fem millisekunder större än starttiden plus fem. Om du kör detta skript flera gånger kan du få olika resultat.
På min maskin skapade jag mellan 6 och 20 filer på fem millisekunder. Intressant, om du försöker lägga till console.log
in i antingen testfunktionen eller den asynkrona funktionen får du mycket olika resultat eftersom det tar tid att skriva till konsolen. Det går bara att visa att i mjukvara har allt en prestationskostnad!
Den för varje slinga är en praktisk struktur - det låter dig göra något för varje objekt i en matris. I async.js skulle detta vara async.each
fungera. Den här funktionen tar tre argument: samlingen eller arrayen, den asynkrona funktionen som ska utföras för varje objekt och den färdiga återuppringningen.
I exemplet nedan tar vi en rad strängar (i detta fall sorters hundraser) och skapar en fil för varje sträng. När alla filer har skapats, körs den återuppringda återuppringningen. Som du kan förvänta dig hanteras fel via fela
objekt i den färdiga återuppringningen. async.each
körs parallellt, men om du vill köra den i serie kan du följa det tidigare nämnda mönstret och använda async.eachSeries
istället för async.each
.
var async = kräver ('async'), fs = kräver ('fs'); async.each (// en rad hundarhundar, "hundghund", "saluki", "borzoi", "galga", "podenco", "whippet", "lurcher", "italian-greyhound"), funktion dogBreed, callback) fs.writeFile (dogBreed + '.txt', // det nya filnamnet 'fil för hundar av rasen' + dogBreed, // innehållet i den nya filåterkallelsen);, funktion (err) om (err) console.error (err); else console.log ('Klar skrivande filer om hundar.'););
En kusin av async.each
är async.map
fungera; Skillnaden är att du kan skicka värdena tillbaka till din färdiga återuppringning. Med async.map
funktion, passerar du i en array eller samling som det första argumentet, och sedan körs en asynkron funktion på varje objekt i matrisen eller samlingen. Det sista argumentet är den färdiga återuppringningen.
Exemplet nedan tar en rad hundraser och använder varje objekt för att skapa ett filnamn. Filnamnet skickas sedan till fs.readFile
, där den läses och värdena skickas tillbaka av återuppringningsfunktionen. Du hamnar ihop med en rad filinnehåll i de färdiga återkallningsargumenten.
var async = kräver ('async'), fs = kräver ('fs'); async.map ("greyhound", "saluki", "borzoi", "galga", "podenco", "whippet", "lurcher", "italian-greyhound"), funktion (dogBreed, callback) fs.readFile (dogBreed + '. txt', // det nya filnamnet 'utf8', callback);, funktion (err, dogBreedFileContents) om (err) console.error (err); else console.log raser "); console.log (dogBreedFileContents););
async.filter
är också mycket liknande i syntax till async.each
och async.map
, men med filter skickar du ett booleskt värde till återuppringningen av objektet istället för värdet på filen. I den färdiga återuppringningen får du en ny uppsättning, med endast de element som du passerade en Sann
eller sanningsvärde för i återuppringningen.
var async = kräver ('async'), fs = kräver ('fs'); async.filter ("greyhound", "saluki", "borzoi", "galga", "podenco", "whippet", "lurcher", "italian-greyhound"), funktion (dogBreed, callback) fs.readFile (dogBreed + '.txt', // det nya filnamnet 'utf8', funktion (err, fileContents) om (err) callback (err); annars callback (err, // det här kommer att vara falskt sedan vi kollade det är ovanför fileContents.match (/ greyhound / gi) // använd RegExp för att söka efter strängen "greyhound" i innehållet i filen););, funktion (err, dogBreedFileContents) om (err) konsol .error (err); else console.log ('greyhound raser:'); console.log (dogBreedFileContents););
I det här exemplet gör vi några fler saker än i tidigare exempel. Lägg märke till hur vi lägger till ett extra funktionssamtal och hanterar vårt eget fel. De om
fela
och callback (err)
mönstret är mycket användbart om du behöver manipulera resultatet av en asynkron funktion, men du vill ändå låta async.js hantera felen.
Dessutom kommer du märka att vi använder err-variabeln som det första argumentet till återuppringningsfunktionen. Vid första rodnad ser det inte rätt ut. Men eftersom vi redan har kontrollerat sanningen av fel, vet vi att det är falskt och säkert att skicka till återkallelsen.
Hittills har vi undersökt ett antal användbara byggstenar som har grova följder i synkron programmering. Låt oss dyka rätt in i async.waterfall
, som inte har mycket av ett ekvivalent i den synkrona världen.
Konceptet med ett vattenfall är att resultaten av en asynkron funktion flyter in i argumenten för en annan asynkron funktion i serie. Det är ett mycket kraftfullt koncept, särskilt när man försöker kombinera flera asynkrona funktioner som bygger på varandra. Med async.waterfall
, Det första argumentet är en rad funktioner, och det andra argumentet är din färdiga återuppringning.
I din uppsättning funktioner börjar den första funktionen alltid med ett enda argument, återuppringningen. Varje efterföljande funktion bör matcha de icke-felaktiga argumenten i den föregående funktionen sans err-funktionen och med tillägget av den nya återuppringningen.
I vårt nästa exempel börjar vi kombinera vissa begrepp med vattenfall som en lim. I det array som är det första argumentet har vi tre funktioner: den första laddar kataloglistan från den aktuella katalogen, den andra tar kataloglistan och användningen async.map
att springa fs.stat
på varje fil och den tredje funktionen tar kataloglistan från det första funktionsresultatet och får innehållet för varje fil (fs.readFile
).
async.waterfall
kör varje funktion i följd, så det kommer alltid att köra alla fs.stat
fungerar innan du kör någon fs.readFile
. I det här första exemplet är de andra och tredje funktionerna inte beroende av varandra så att de kan vara inslagna i en async.parallel
för att minska den totala körtiden, men vi ändrar den här strukturen igen för nästa exempel.
Notera: Kör detta exempel i en liten katalog med textfiler, annars kommer du att få mycket skräp länge i ditt terminalfönster.
var async = kräver ('async'), fs = kräver ('fs'); async.waterfall ([funktion (återuppringning) fs.readdir ('.', callback); // läs den aktuella katalogen, överför den till nästa funktion., funktion (filnamn, återuppringning) // 'fileNames' är kataloglistan från föregående funktion async.map (fileNames, // Kataloglistan är bara en uppsättning filnamn, fs.stat, // så vi kan använda async.map för att köra fs.stat för varje filnamnsfunktion (fel , state) if (err) callback (err); annars callback (err, filnamn, statistik); // passera felet, kataloglistan och statkollektionen till nästa objekt i vattenfallet) ;, funktion (filnamn, statistik, återuppringning) // kataloglistan, 'filnamn' förenas av samlingen av fs.statobjekt i 'statistik' async.map (filnamn, funktion (aFileName, readCallback) // Den här gången tar vi filnamnen med kartan och skickar dem vidare till fs.readFile för att få innehållet fs.readFile (aFileName, 'utf8', readCallback);, funktion (fel, innehåll) om (err) callback (err); else // Nu är vår återuppringning w Ill har tre argument, den ursprungliga kataloglistan ("filenNames"), fs.stats-samlingen och en rad med innehållet i varje återuppringning av filer (fel, filnamn, statistik, innehåll); ); ], funktion (fel, filnamn, statistik, innehåll) if (err) console.error (err); annat console.log (filnamn); console.log (statistik); console.log (innehåll); );
Låt oss säga att vi vill få resultatet av endast de filer som har en storlek över 500 byte. Vi skulle kunna använda ovanstående kod, men du skulle få storleken och innehållet i varje fil, oavsett om du behövde dem eller inte. Hur kan du bara få statens filer och bara innehållet i filerna som når storlekskraven?
Först kan vi dra alla anonyma funktioner ut i namngivna funktioner. Det är personlig preferens, men det gör koden lite renare och lättare att förstå (återanvändbar för att starta). Som du kanske kan tänka dig måste du få storlekarna, utvärdera storlekarna och få bara innehållet i filerna ovanför storlekskravet. Detta kan enkelt uppnås med något liknande Array.filter
, men det är en synkron funktion, och async.waterfall förväntar sig asynkron-stilfunktioner. Async.js har en hjälparfunktion som kan svepa synkrona funktioner i asynkrona funktioner, den ganska jazzily namngiven async.asyncify
.
Vi måste göra tre saker, som vi kommer att pakka med async.asyncify
. Först tar vi filnamn och statrapporter från arrayFsStat
funktionen, och vi sammanfogar dem med Karta
. Då filtrerar vi bort alla objekt som har en statstorlek mindre än 300. Slutligen tar vi det kombinerade filnamnet och statobjektet och använder Karta
igen för att bara hämta filnamnet.
När vi har namnen på filerna med en storlek mindre än 300 använder vi async.map
och fs.readFile
för att få innehållet. Det finns många sätt att spricka detta ägg, men i vårt fall blev det uppbrutet för att visa maximal flexibilitet och kodåteranvändning. Detta async.waterfall
användning illustrerar hur du kan mixa och matcha synkron och asynkron kod.
var async = kräver ('async'), fs = kräver ('fs'); // Vår anonyma refactored till namngiven funktioner funktion directoryListing (callback) fs.readdir ('.', Callback); funktion arrayFsStat (filnamn, återuppringning) async.map (filnamn, fs.stat, funktion (err, statistik) om (err) callback (err); else callback (err, filnamn, statistik); ); funktion arrayFsReadFile (filnamn, återuppringning) async.map (fileNames, function (aFileName, readCallback) fs.readFile (aFileName, 'utf8', readCallback);, funktion (fel, innehåll) om (err) callback (err); else callback (fel, innehåll);); // Dessa funktioner är synkron funktion MergeFilenameAndStat (filnamn, statistik) return stats.map (funktion (aStatObj, index) aStatObj.fileName = fileNames [index]; returnera aStatObj;); funktion över300 (combinedFilenamesAndStats) return combinedFilenamesAndStats .filter (funktion (aStatObj) return aStatObj.size> = 300;); funktion justFilenames (combinedFilenamesAndStats) return combinedFilenamesAndStats .map (funktion (aCombinedFileNameAndStatObj) return aCombinedFileNameAndStatObj.fileName;); async.waterfall ([directoryListing, arrayFsStat, async.asyncify (mergeFilenameAndStat), // asyncify omsluter synkrona funktioner i en err-första återuppringning async.asyncify (above300), async.asyncify (justFilenames), arrayFsReadFile] innehåll) om (err) console.error (err); annat console.log (innehåll););
Med ett steg längre, låt oss förfina vår funktion ännu längre. Låt oss säga att vi vill skriva en funktion som fungerar exakt som ovan, men med flexibiliteten att titta på vilken väg som helst. En nära kusin till async.waterfall är async.seq
. Medan async.waterfall
exekverar bara ett vattenfall av funktioner, async.seq
returnerar en funktion som utför ett vattenfall av andra funktioner. Förutom att skapa en funktion kan du skicka in värden som går in i den första asynkronfunktionen.
Konvertering till async.seq
tar bara några ändringar. Först ska vi ändra directoryListing
att acceptera ett argument - det här kommer att vara vägen. För det andra lägger vi till en variabel för att hålla vår nya funktion (directoryAbove300
). Tredje, vi tar array argument från async.waterfall
och översätt det till argument för async.seq
. Vårt återuppringning för vattenfallet används nu som den färdiga återuppringningen när vi kör directoryAbove300
.
var async = kräver ('async'), fs = kräver ('fs'), katalogAbove300; funktion directoryListing (initialPath, callback) // vi kan skicka en variabel till den första funktionen som används i async.seq - den resulterande funktionen kan acceptera argument och ge dem den första funktionen fs.readdir (initialPath, callback); funktion arrayFsStat (filnamn, återuppringning) async.map (filnamn, fs.stat, funktion (err, statistik) om (err) callback (err); else callback (err, filnamn, statistik); ); funktion arrayFsReadFile (filnamn, återuppringning) async.map (fileNames, function (aFileName, readCallback) fs.readFile (aFileName, 'utf8', readCallback);, funktion (fel, innehåll) om (err) callback (err); else callback (fel, innehåll);); funktion mergeFilenameAndStat (filnamn, statistik) return stats.map (funktion (aStatObj, index) aStatObj.fileName = fileNames [index]; returnera aStatObj;); funktion över300 (combinedFilenamesAndStats) return combinedFilenamesAndStats .filter (funktion (aStatObj) return aStatObj.size> = 300;); funktion justFilenames (combinedFilenamesAndStats) return combinedFilenamesAndStats .map (funktion (aCombinedFileNameAndStatObj) return aCombinedFileNameAndStatObj.fileName; //async.seq kommer att producera en ny funktion som du kan använda om och om katalogenAbove300 = async.seq (directoryListing, arrayFsStat, async.asyncify (mergeFilenameAndStat), async.asyncify (above300), async.asyncify (justFilenames), arrayFsReadFile); directoryAbove300 ('.', funktion (err, filnamn, statistik, innehåll) if (err) console.error (err); else console.log (filnamn););
Du kanske undrar varför jag inte har nämnt löften. Jag har ingenting mot dem-de är ganska praktiska och kanske en mer elegant lösning än callbacks-men de är ett annat sätt att titta på asynkron kodning.
Inbyggda Node.js moduler använder fela
-första återuppringningar och tusentals andra moduler använder detta mönster. Det är faktiskt därför det här handledningen använder fs
i exemplen - något som är så grundläggande som filsystemåtkomst i Node.js använder återuppringningar, så det är en väsentlig del av Node.js-programmering.
Det är möjligt att använda något som Bluebird för att sätta in err-första återuppringningar till Promise-baserade funktioner, men det får bara dig så långt. Async.js ger en mängd metaforer som gör asynkron kod läsbar och hanterbar.
JavaScript har blivit ett av de faktiska språken för att arbeta på webben. Det är inte utan sina inlärningskurvor, och det finns gott om ramar och bibliotek för att hålla dig upptagen också. Om du letar efter ytterligare resurser att studera eller använda i ditt arbete, kolla vad vi har tillgängligt på Envato-marknaden.
Men att lära sig asynkron är något helt annat, och förhoppningsvis har denna handledning visat dig hur nytta det kan vara.
Asynkron är nyckeln till att skriva på serversidan-JavaScript, men om det inte är utformat korrekt kan din kod bli ett oövervakbart odjur av återuppringningar. Genom att använda ett bibliotek som async.js som ger ett antal metaforer, kanske du tycker att skrivande asynkron kod är en glädje.