Promises
Promises
Návrhový vzor pro CPS
Ondřej Žára, Seznam.cz
Bojový plán
- Problémy asynchronních funkcí
- Promise: zobecněný callback
- Pokročilé partie
Problémy asynchronních funkcí
Problémy asynchronních funkcí
var output = computeStuff(input);
var output = requestStuff(input, callback);
- Výsledek práce funkce není znám ve chvíli jejího ukončení
- Návratová hodnota je zpravidla bezvýznamná
- Předáním callbacku ztrácíme kontext (pokud nepoužijeme bind)
- Co když "zpožděná" část funkce vyhodí výjimku?
Problémy asynchronních funkcí
- Jak zřetězit (serializovat) více asynchronních volání?
- Co když je funkce asynchronní podmíněně?
- Co když asynchronní funkci zavolám opakovaně?
- Kdo určuje signaturu callbacku?
- Jak v kódu nahradit synchronní volání voláním asynchronním?
Promise: zobecněný callback
Starý dobrý callback
- Předávat callback (+ volitelně kontext) je tradiční řešení
- Události, setTimeout, XHR, …
- Zpravidla stačí, ale je neobratný
Promise: zobecněný callback
- Promises jsou návrhový vzor
- Asynchronní funkce nepřijímá callback, namísto toho vrací "budoucí hodnotu" (promise)
- Promise popisuje hodnotu, která ještě nebyla nalezena (ale časem bude)
- Když mám Promise, můžu ji poprosit o vykonání callbacku
Promise: základní použití
var requestData = function() {
var promise = new JAK.Promise();
/* var xhr = ... */
xhr.addEventListener("ready", function(data) {
promise.fulfill(data);
});
/* xhr.send() */
return promise;
}
Promise: základní použití
var promise = requestData();
promise.then(callback);
promise.then(jinyCallback);
Promise: opáčko
new JAK.Promise()
je obecná neznámá hodnota
promise.fulfill(data)
posune promise do stavu "splněno" (max. jednou)
promise.then(cb)
je zavěšení posluchače
- Posluchačů lze zavěsit více
- Posluchač bude vykonán vždy s jedním parametrem (tím, co dostane
fulfill
)
Promise: návratová hodnota then
- Metoda
then
vrací další Promise
- Tím se celá věc nečekaně komplikuje :-)
- Nová promise, vrácená
then
, bude fulfillnuta hodnotou vrácenou callbackem
- Pokud callback vrátí Promise (třetí), ta druhá bude fulfillnuta až po jejím splnění
Promise: návratová hodnota then
var promise = requestData1();
promise.then(requestData2).then(requestData3).then(...);
/* requestData{1..3} vrací promise.
Kdyby náhodou třeba requestData2 vrátila rovnou výsledek,
nic by se nerozbilo (ale requestData3 by bylo voláno ihned).
*/
Pokročilé partie
Pokročilé partie: pořadí volání
- Promise je možno splnit (
fulfill
) ještě před voláním then
- Tato varianta odpovídá synchronnímu volání (výsledek známe v době skončení funkce)
- Callback předaný do
then
bude ovšem volán asynchronně (setTimeout(0))
- To proto, že volající nemusí vědět, kdy bude hodnota známa
Pokročilé partie: reject
- Promise má ještě metodu
reject(reason)
- Změna stavu promise na "selhalo"
- Metoda
then
má volitelný druhý callback pro případ selhání
- Alternativa pro asynchronní propagaci chyb
Pokročilé partie: reject
var request = function() {
var promise = new JAK.Promise();
xhr.onreadystatechange = function() {
if (xhr.status == 200) { promise.fulfill(); } else { promise.reject(); }
}
return promise;
}
var promise = request();
promise.then(zpracujData, vypisChybu);
Pokročilé partie: when
- Statická metoda
when
dostane pole promisů a vrátí novou
- Tato bude fullfillnuta pole fullfillment values, jakmile dojde ke splnění celého pole
- Pokud jedna z pole rejectne, tato
when
bude rejectnuta
Rekapitulace
Rekapitulace
- Promises jsou volitelnou alternativou k předávání callbacků
- Promises musí "někdo" vracet a "někdo jiný" zpracovávat
- Promise si sama řeší libovolný počet "posluchačů", async. fci to nezajímá
- Volání
.then()
lze řetězit
- Callback v
then
je vždy volán s parametrem, který vrátilo předchozí volání
- Pokud callback vrátí Promise, pokračování volání dalších
then
je navázáno na její fulfill
/reject
- I synchronní funkce může vrátit Promise