Přejít k navigační liště

Zdroják » JavaScript » Dart – Futures

Dart – Futures

Články JavaScript

Webový vývojár dennodenne pracuje s ajaxovými requestami, callbackmi, obsluhovaním eventov. Neblokujúce API je v Javascripte štandardom, no nie je vždy úplne najpohodlnejšie používať ho. Dart rieši asynchrónne operácie pomocou Futures.

Predstavme si, že máme sadu asynchrónnych operácií, ktoré potrebujeme vykonať v presne danom poradí. Typické riešenie pomocou callbackov by vyzeralo nasledovne:

void main() {
  ajaxA(onSuccess: (resultA) {
    ajaxB(onSuccess: (resultB) {
      ajaxC(onSuccess: (resultC) {
        handleC(resultC);
      }, onError: () => handleError());
    }, onError: () => handleError());
  }, onError: () => handleError());
}

Takýto kód nie je úplne prehľadný.

Použime Futures!

V Darte asynchrónne operácie neočakávajú callback, miesto toho vracajú objekt typu Future, tento objekt slúži ako akási reprezentácia hodnoty spočítanej v budúcnosti. Na Future vieme pomocou metódy then navesiť callback, ktorý sa zavolá v momente, ako bude aktuálna hodnota k dispozícii.

void main() {
  var future = ajax();
  var futureAlert = future.then((result) => "Success is performed by $result"));
  futureAlert.then((value) => alert(value));
}

Vo vyššie uvedenom príklade sme do premennej future priradili výsledok asynchrónnej operácie ajax(). Následne sme cez future.then navesili callback, ktorý vezme spočítanú hodnotu result a vráti ju vo forme stringu (použité string interpolation). Všetko vrátené z callbacku vnútri then handlera sa považuje za ďalšiu Future, v našom prípade futureAlert. Na futureAlert navesíme jednoduchý then handler, ktorý alertne hodnotu.

Pre prípad, že nastane počas vyhodnocovania Future nejaká chyba, môžeme ju zachytiť pomocou catchError. Ak chceme zaregistrovať funkciu, ktorá sa vykoná v prípade chyby, no aj v prípade úspechu, môžeme použiť whenComplete.

void main() {
  var future = ajax();
  future.then((value) => handleValue(value))
        .catchError((error) => handleError()))
        .whenComplete(() => alert("This is like finally!");

}

Použitie pripomína klasický trycatchfinally blok a tak ho treba aj chápať – ako spôsob zápisu asynchrónneho obsluhovania výnimiek.

Poďme sa teraz pozrieť, ako pomocou Futures môžeme zjednodušiť náš pôvodný kód.

void main() {
  ajaxA().then((resultA) => ajaxB())
         .then((resultB) => ajaxC())
         .then((resultC) => handleC(resultC))
         .catchError((error) => handleError())

Pri pozornejšom zamyslení sa nie je úplne jasné, prečo by mal uvedený kód fungovať tak, ako by sme chceli. Volanie ajaxB() nevracia hodnotu, ale Future a podla toho, čo sme si povedali, by táto Future mala byť obalená v ďalšej Future, ktorú vráti volanie then.

Toto je našťastie vyriešené šikovne. Metóda Future then(onValue(T value)) po zavolaní vráti Future f, ktorá bude ukončená s výsledkom volania callbacku onValue. V prípade, že onValue vráti Future f2, f je zreťazená s f2, čo znamená, že f je ukončená až v momente, kedy je ukončená f2 a to s rovnakým výsledkom ako f2. Toto nám umožňuje reťaziť Futures tak, ako v príklade.

Na poradí nezáleží.

Predstavme si inú situáciu. Náš kód potrebuje vykonať viacero asynchrónnych volaní, ktoré sú na sebe úplne nezávislé, no nemôžeme pokračovať skôr, ako budú dokončené. Ako efektívne vyriešiť toto?

void main() {
  Future.wait([ajaxA(), ajaxB(), ajaxC()])
        .then((values) => alert("A: ${values[0]}, B: ${values[1]}, C: ${values[2]}"))
        .catchError((error) => handleError());
}

Statická metóda Future.wait očakáva List futures a výsledkom je Future, ktorá je ukončená v momente, kedy je ukončený posledný prvok vo futures. Výsledkom je List hodnôt s ktorými jednotlivé prvky futures skončili.

Chceme vlastné.

Naučili sme sa používať Futures, vyrábať ich je ešte jednoduchšie. Stačí využiť služby predpripravenej triedy Completer.

Future ajaxA() {
  var completer = new Completer();
  doSomeAjaxRequest(onSuccess: (result) {
    completer.complete(result);
  }, onError: () {
    completer.completeError(new Exception("Error!"))
  });

  return completer.future;
}

Completer vlastní property future, ktorú z funkcie ajaxA vraciame. V momente, kedy doSomeAjaxRequest (ne)úspešne dobehne, ukončí Completer future (ne)úspešne pomocou metódy complete , respektíve completeError.

Feedback prosím!

Nájdite si prosím chvíľu času na ohodnotenie tohto článku.

Zdroje

Pri písaní článku som čerpal z viacerých hodnotných zdrojov, nižšie ich nájdete zoradené podľa užitočnosti, zaujímavosti a aktuálnosti.

Komentáře

Subscribe
Upozornit na
guest
6 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
Pavel Dvořák

Nelíbí se mi, že již v pátém díle seriálu je rozebrán obvyklý, ale krkolomný a zákeřný problém pro nováčky, aniž by čtenářům byly komplexně představeny základní principy jazyka. Byť jsou celkem podobné s klasickou céčkovou syntaxí, musí mít také nějaká specifika, přece to není jenom kompilátor C do JavaScriptu. Víte, jak to myslím, stačí takovéty klasické podmínky, hlášky, události, práce s html objekty, větvení, časování, apod. Sice v úvodu do seriálu bylo něco málo naznačeno ohledně funkcí a proměnných a postupně jsme při vytváření hry, přemýšlení o DOMu a zkoumání AJAXových struktur prošli mnoho příkladů a ukázek kódu a napsali několik aplikací, ale to nás nenaučilo řešit vlastní problém. Jakožto člověk, který se o to zajímá a se okolo webů pohybuje už nějakou dobu, jsem samozřejmě hned po 2. článku listoval dokumentací Dartu. Ale pro nováčky to může být problém. Navíc jste první, kdo Dart v Čechách podrobně rozpracovává a protože je to docela přívětivý jazyk i k nováčkům, stálo by za to také je trochu uvést do problematiky. Osobně mě tento poslední článek ničím už nezaujal a zdá se, že teď už budu muset spoléhat jen a jen na dokumentaci v angličtině, protože po dnešním článku si nejsem jist, budou-li mi další díly vůbec k něčemu, byť jsem úvod do jazyka doslova hltal. První články jsem si pročítal znovu a znovu, ale základní syntaxi a právě ta zajímavá pravidla větvení jsem vyčetl opravdu pouze z ukázek, již ne však z textu. Praxí a ukázkami je to parádní seriál na nové téma, ale zapomenulo se vlastně úplně na trochu té důležité teorie, což je podle mě škoda.
Moje hodnocení článků (jako ve škole):
1. díl: 1
2. díl: 1
3. díl: 3
4. díl: 3
5. díl: 4

Martin Hassman

Jak já to vidím, seriál vás dost oslovil, inspiroval a skvěle navnadil, takže jste se chopil iniciativy a vrhl se do problematiky. To je skvělé! Cíl dosažen. Mise splněna. Co mi uniká? 8-)

Pavel Dvořák

Já ano, jen si myslím, že někdo méně zkušený již ne…

apir

Podla mna tiez nema zmysel roztahovat serialy na 3 nasobnu dlzku tym, ze sa bude ucit zakladna syntax. Ovela efektivnejsie mi pride, ked sa vysvetluju hlavne specifika a celkova filozofia vyvoja.

Mimochodom, tym, ktori chcu rychlo vstrebat zakladnu syntax Dartu odporucam tieto videa: https://www.dartlang.org/dart-tips/ . Je to pozeranie asi na hodinu a dobry doplnok k temam tohto serialu.

blizz

tie futures su tiez dost neprehladne, prirodzenejsi mi pride C#kovy await

//C#
var result = await webClient.DownloadStringAsync(„http://REFRESHER.SK/“);

alebo F# – kove asynchronne workflows:

//F#
let! result = webClient.AsyncDownloadString „http://REFRESHER.SK/“

crossborne

Ještě bych dodal, že to není jen vychytávkou Dartu, ale spíš obecný návrhový vzor… Btw v Dartu tomu taky říkali promises než se to přejmenovalo http://news.dartlang.org/2012/02/library-change-promise-out-future-in.html

Doporučuji to používat i v javascriptu http://www.slideshare.net/async_io/javascript-promisesq-library-17206726, vyvarujete se tak spaghetti/messy kódu.

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.

Pocta C64

Za prvopočátek své programátorské kariéry vděčím počítači Commodore 64. Tehdy jsem genialitu návrhu nemohl docenit. Dnes dokážu lehce nahlédnout pod pokličku. Chtěl bych se o to s vámi podělit a vzdát mu hold.