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') })