Ez a cikk az async/ await kulcsszavakkal kapcsolatos tapasztalataimról szól, amelyeket nemrég kezdtem el használni, mivel a Node 8.0.0+ teljes mértékben támogatja azt (főleg TypeScriptben, de szerintem az egész koncepciót vonatkozik az ES6-ra is).
Az Async/await funkcióval az aszinkron kód egy kicsit jobban hasonlít a szinkron kódhoz. Ebben rejlik minden ereje.
Az async/await használata egyszerű. Csak létrehozhat aszinkron funkciót, és a hívások előtt meghívhat más aszinkron függvényeket a várakozás kulcsszóval.
Így a várakozás és a hívás után minden úgy viselkedik, mintha a downloadData()
által visszaadott Promise then()
kezelőjében lenne.
A következő példában látható módon „klasszikus visszahívásként” is megvalósítható lett volna:
Mivel a szintaxis nagyon szép és egyszerű, nagyon könnyű megszokni await
az összes hálózati és I/O hívást.
Legyen azonban óvatos, ha egymás után többször használja, mivel a await
kulcsszó leállítja az utána következő kódok végrehajtását. (Pontosan olyan, mint a szinkron kódban)
A következő példában a kód nagyon tiszta és szép (ellentétben a visszahívási pokollal), de csendben is soros lett.
Ez azt jelenti, hogy a downloadFromService2()
metódus nem kerül meghívásra, és a második kérés nem kerül elküldésre, mielőtt az adatok letöltődnek az 1. szolgáltatásból.
A downloadFromService3()
függvényt sem hívják meg, mielőtt a downloadFromService2()
befejeződik.
Képzeld el, ha az összes szolgáltatásnak ~100 ms válaszideje lenne. Akkor az egész processData()
metódus több mint ~300ms-t vesz igénybe!
Nem ezt akarjuk és nem várjuk el az „eseményvezérelt, nem blokkoló I/O modelltől”. Ezenkívül egyáltalán nem kell megvárni az első kérés befejezését, mivel egyetlen más kérés sem függ annak eredményétől.
Szeretnénk, ha a kéréseket párhuzamosan küldenék el, és várnánk, hogy mindegyik egyszerre fejeződjön be. Itt rejlik az aszinkron eseményvezérelt programozás ereje.
Ennek kijavításához használhatjuk a Promise.all()
metódust. Mentjük az ígéreteket az aszinkronfüggvényhívásokból változókra, egyesítjük őket egy tömbbe, és egyszerre várjuk őket.
Ez azonban csak akkor működik, ha minden kérésünk nem függő.
A való életben általában néhány aszinkronhívásunk a korábbi hívások eredményétől függ, mások pedig nem.
A következő szabályokat használhatjuk, ha a lehető legkisebb késleltetési / kérési időre szeretnénk törekedni:
- a lehető leghamarabb hívja meg az async függvényeket, és mentse el a visszaadott ígéreteket változó(k)ba
- A lehető legkésőbb várja meg a mentett ígéreteket
A valós életben való felhasználást a következő példa szemlélteti a bejegyzés adatbázisból való eltávolításával.
Először is minden lehetséges aszinkronhívást végrehajtunk. Ebben az esetben ez azt jelenti, hogy fel kell hívni az adatbázist a Hozzászólásobjektum lekéréséhez, valamint az engedélyezési szolgáltatást.
Ezután várjuk a permissionsPromise
-et, mert a következő teendőnk az, hogy ellenőrizzük, hogy a felhasználó valóban eltávolíthatja-e a bejegyzéseket.
Amíg az engedély-ellenőrzés befejezésére várunk, a Bejegyzésobjektumlekérése folyamatban van a háttérben lévő adatbázisból.
Ha az engedélyellenőrzés sikeres volt, a Hozzászólás objektum lekérésével folytatjuk. Ezt úgy tesszük, hogy várunk postPromise
-re, és valószínű, hogy a bejegyzés már le van töltve.
Ha ez a helyzet, a várni azonnal visszatér.
Nem egyszerűen meghívjuk a sendRemoveRequest()
-t a lekért Post objektummal.
A await kulcsszó megfelelő használatával körülbelül 200 ms-ot sikerült megtakarítanunk minden egyes remove_post
kérésből. Zseniális!