Logo preloader Xtension

JavaScript: async/await, Promise i Observable

callbackHell1(function(result1) { callbackHell2(function(result2) { callbackHell3(function(result3) { //etc…. }); }); });
javascript
coding
markus-spiske-AaEQmoufHLk-unsplash

callbackHell1(function(result1) {

 callbackHell2(function(result2) {

  callbackHell3(function(result3) {

  //etc….

  });

 });

});

 

Poniżej ten sam przykład z użyciem obietnic:

callbackHell1().then(function(result1) {

 return callbackHell2();

}).then(function(result2) {

 return callbackHell3();

}).then(function(result3) {

 //etc…

});

 

Już na tym etapie jest dobrze. Ale może być jeszcze lepiej. Zobaczmy, jak to będzie wyglądać, gdy użyjemy await:

 

const result1 = await callbackHell1();

const result2 = await callbackHell2();

const result3 = await callbackHell3();

 

Idealnie. Wszystko jest teraz jasne i przejrzyste. Należy pamiętać, że to wszystko jest tylko „syntaktycznym lukrem”, a pod spodem kod wykonuje się rzeczywiście asynchronicznie. Co najważniejsze, słowa await możemy użyć wyłącznie w kontekście funkcji, która będzie oznaczona słowem kluczowym async.

 

async function asyncHeaven(){

 return await callbackHell1();

}

 

I jeszcze jedna ważna rzecz – te słowa kluczowe współpracują wyłącznie z obietnicami. A więc await możemy postawić przed wywołaniem, które zwraca Promise, a funkcja oznaczona przez async musi zwrócić również Promise.

 

Kilka słów o Observable

 

Gdy ponad rok temu zawodowo zetknąłem się z Angularem, i to od razu w wersji 5, a wraz z nim z biblioteką rxjs, pomyślałem że Observable to nowy lepszy Promise. Zwłaszcza, że Angular promuje te pierwsze w nowym kliencie http. Wydawało mi się wówczas naturalne, żeby również w projekcie, w którym jestem zaangażowany, forsować stosowanie Observable. Chociażby dlatego, by w całym projekcie w spójny sposób obsługiwać asynchroniczny kod. Udawało się to z większym lub mniejszym powodzeniem. Ale zacząłem dostrzegać też pewne niedogodności.
Podstawową różnicą w działaniu Observable jest to, że jeżeli nie wywołamy na nim metody subscribe, wówczas asynchroniczna metoda się nie wykona. Przykładem jest http.get:

 

import { HttpClient } from '@angular/common/http';

@Injectable()

export class TestowyService {

 constructor(private http: HttpClient) {}

 public getConfig(): Observable < any > {

  return this.http.get(‘jakiśurl’);

 }

}

 

Jeżeli w powyższym przykładzie nie zasubskrybujemy wyniku metody, wówczas do serwera nie pójdzie żądanie GET. Może to czasami być zaletą, ale jeżeli do tej pory ktoś korzystał z obietnic, to może się zdziwić, bo nie mamy obowiązku wywoływać then.

Druga sprawa to fakt, że te obiekty nie są częścią języka, w związku z tym nie są wprost wspierane przez async/await. Aby to zrobić, musimy najpierw przekonwertować do obietnicy za pomocą metody toPromise.

Nie jest to wszystko szczególnie uciążliwe, ale pokazuje, że nie ma sensu na siłę korzystać z „obserwabli”. Są oczywiście sytuacje, gdy obietnice nie znajdują zastosowania, a obiekty z biblioteki rxjs są wówczas niezastąpione.

Data publikacji: 19 czerwca 2018
Autor: Michał Gierwatowski
Przeczytaj kolejne artykuły
shutterstock_1931013749
Mobile
Certum
Security
signaturiX. Podpisuj na swoim smartfonie!
altumcode-U0tBTn8UR8I-unsplash
Mobile
Certum
Security
Czy warto używać lodash?
Water-Scrum-Fall. Inicjacja czy dojrzałość
Mobile
Certum
Security
Water-Scrum-Fall. Inicjacja czy dojrzałość?
Stwórzmy razem wyjątkowy projekt
Napisz do nas

Xtension Sp z o.o.

ul. Opacka 12

80-338 Gdańsk

 

+48 58 351 39 66

biuro@xtension.pl

 

LinkedIn