Tak, obietnice są asynchronicznymi wywołaniami zwrotnymi. Nie mogą zrobić niczego, czego nie mogą zrobić wywołania zwrotne, a ty masz do czynienia z tymi samymi problemami z asynchronicznością, co z zwykłymi wywołaniami zwrotnymi.
Jednak obietnice są czymś więcej niż tylko wywołaniami zwrotnymi. Są bardzo potężną abstrakcją, pozwalają na czystszy i lepszy, funkcjonalny kod z mniej podatną na błędy płytą kotłową.
Więc jaki jest główny pomysł?
Obietnice są obiektami reprezentującymi wynik pojedynczego (asynchronicznego) obliczenia. Oni rozwiązać do tego wyniku tylko raz. Jest kilka rzeczy, co to oznacza:
Obietnice wdrażają wzorzec obserwatora:
- Nie musisz znać wywołań zwrotnych, które wykorzystają tę wartość przed zakończeniem zadania.
- Zamiast oczekiwać wywołań zwrotnych jako argumentów dla twoich funkcji, możesz łatwo
return
stworzyć obiekt Promise
- Obietnica zapisze wartość i możesz w sposób przezroczysty dodać oddzwonienie, kiedy tylko chcesz. Zostanie wywołany, gdy wynik będzie dostępny. „Przejrzystość” oznacza, że kiedy masz obietnicę i dodajesz do niej wywołanie zwrotne, nie ma znaczenia dla twojego kodu, czy wynik już dotarł - interfejs API i umowy są takie same, znacznie upraszczając buforowanie / zapamiętywanie.
- Możesz łatwo dodawać wiele połączeń zwrotnych
Obietnice są łańcuchowe ( monadyczne , jeśli chcesz ):
- Jeśli trzeba przekształcić wartość obietnica oznacza, ty map funkcję przekształcić na obietnicy i wrócić nową obietnicę, że reprezentuje przekształcony wynik. Nie możesz synchronicznie uzyskać wartości, aby jakoś z niej skorzystać, ale możesz łatwo podnieść transformację w kontekście obietnicy. Brak wywołań zwrotnych płyty kotłowej.
- Jeśli chcesz połączyć dwa zadania asynchroniczne, możesz użyć tej
.then()
metody. Wywołanie zwrotne zostanie wywołane z pierwszym wynikiem i zwróci obietnicę dotyczącą wyniku obietnicy, którą zwraca wywołanie zwrotne.
Brzmi skomplikowanie? Czas na przykładowy kod.
var p1 = api1(); // returning a promise
var p3 = p1.then(function(api1Result) {
var p2 = api2(); // returning a promise
return p2; // The result of p2 …
}); // … becomes the result of p3
// So it does not make a difference whether you write
api1().then(function(api1Result) {
return api2().then(console.log)
})
// or the flattened version
api1().then(function(api1Result) {
return api2();
}).then(console.log)
Spłaszczanie nie przychodzi magicznie, ale możesz to łatwo zrobić. W przypadku mocno zagnieżdżonego przykładu (prawie) odpowiednikiem byłoby
api1().then(api2).then(api3).then(/* do-work-callback */);
Jeśli zapoznanie się z kodem tych metod pomaga zrozumieć, oto najbardziej podstawowa biblioteka obietnic w kilku wierszach .
O co tyle zamieszania w obietnicach?
Abstrakcja Promise umożliwia znacznie lepszą kompozycyjność funkcji. Na przykład, obok then
łańcucha, all
funkcja tworzy obietnicę dla połączonego wyniku wielu obietnic oczekiwania równoległego.
Wreszcie, obietnice pochodzą ze zintegrowaną obsługą błędów. Wynik obliczeń może być taki, że albo obietnica zostanie spełniona z wartością, albo zostanie odrzucona z uzasadnionego powodu. Wszystkie funkcje kompozycji obsługują to automatycznie i propagują błędy w łańcuchach obietnic, dzięki czemu nie musisz się tym wszystkim przejmować - w przeciwieństwie do implementacji zwykłego wywołania zwrotnego. Na koniec możesz dodać dedykowane wywołanie zwrotne błędu dla wszystkich występujących wyjątków.
Nie wspominając już o konieczności przekształcania rzeczy w obietnice.
To całkiem trywialne w przypadku dobrych bibliotek obietnic, zobacz Jak przekonwertować istniejące API zwrotne na obietnice?