Doprovodný zdrojový kód: {{ :krouzek:async_await_html.zip |}}
=== Intro ===
Většina procedurálních jazyků primárně používá blokující funkce
* čekání na vstup (klávesa, myš) uživatele
* načítání dat ze souboru
* síťové dotazy
Například v pythonu:
jmeno = input('Kdo jsi?\n') # zde se čeká dokud uživatel nenapíše jméno
# teď můžu pracovat s hodnotou proměnné jméno, mám ji načtenou
print(f"Ahoj {jmeno}")
K zajištění asynchronicity (například program něco počítá, ale uživatel dál něco nastavuje v okně programu)
se používají o něco (zápisem) komplikovanější postupy, které vnitřně používají vlákna (thready).
V javascriptu je to opačně. Přirozené použití vede na asynchronitu.
Primárně se používají události (events); na něco jsou skvělé, na jiné věci méně.
Uvnitř funguje jednovláknový "event loop" - ucelené kusy výpočtu se naplánují a postupně vykonají.
=== Eventy ===
* Uživatelské eventy:
* Klik na tlačítko
* Klik na nějaký prvek stránky (případně mousedown, mouseup)
* Přejetí nad prvkem stránky (mouseover)
* Livovolný pohyb myši (mousemove)
* Změna velikosti okna (např. maximalizace)
* keydown, keyup (nebo keypress)
* kliknutí do/z okna (focus, blur)
* Další:
* Stránka byla načtena (load)
* Datový zdroj byl stažen (např. json s mailem) - původní [[https://www.w3schools.com/js/js_ajax_http_response.asp|AJAX]], [[https://www.w3schools.com/js/tryit.asp?filename=tryjs_ajax_xmlhttp|příklad použití]]
=== Callbacky ===
* setTimeout
* setInterval
* rozhraní různých knihoven
Často je výsledkem [[http://callbackhell.com/|callback hell]]
----
Řešení (2012 ale dlouho trvalo než probublalo do prohlížečů)
=== Promises ===
let myPromise = new Promise(function(myResolve, myReject) {
// "Producing Code" (May take some time)
myResolve(); // when successful
myReject(); // when error
});
// "Consuming Code" (Must wait for a fulfilled Promise)
myPromise.then(
function(value) { /* code if successful */ },
function(error) { /* code if some error */ }
);
Zdánlivě jen další příklad callbacku, ale `.then()` lze řetězit
new Promise(function(resolve, reject) {
setTimeout(() => resolve(1), 1000); // (*)
}).then(function(result) { // (**)
alert(result); // 1
return result * 2;
}).then(function(result) { // (***)
alert(result); // 2
return result * 2;
}).then(function(result) {
alert(result); // 4
return result * 2;
});
a existující callback funkce lze převést na promisy
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
const nactiStranku = new Promise(function(myResolve, myReject) {
const xhttp = new XMLHttpRequest();
xhttp.onload = function() {
myResolve(xhttp)
}
xhttp.onerror = function(){
myReject()
}
// Send a request
xhttp.open("GET", "ajax_info.txt");
xhttp.send();
});
=== Async/Await ===
Proč vůbec stále psát ''%%then()%%'' ?
Pojďmě udělat speciální kategorii funkcí, které označíme ''%%async%%''
* Interně vrací Promise.
* Při použití nového klíčového slova ''%%await%%'' se na daném místě "zastaví" (ovšem s uvolněním event loopu) a počká se na splnění promise (např. dotazu na server)
* Neúspěch (reject) Promise => vyplivne výjimku (throw an exception) - lze ji ošetřit pomocí try-catch což je dnes standardní postup většiny jazyků
Příklad výsledného kódu:
const pokemoni = await nactiSeznamPokemonu()
const grafika = await nactiObrazkyPokemonu(pokemoni)
await pockejNaMezeru()
zacniHru()
/* ... */
Jediný implementační problém: ''%%await%%'' může být použit pouze uvnitř asynchronních funkcí.
{{:krouzek:async_await.png|}}
Nejsnazší řešení (ne vždy ideální ;)):
setTimeout(async function(){
// Tady už jsme v async/await prostředí (tato funkce je async)
await sleep(1000)
alert('Hello')
})