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.