Obsługa Promises to bez wątpienia jedna z najważniejszych nowych funkcji języka JavaScript w standardzie ES6. Do czego służą "obietnice"? W skrócie: do zarządzania wynikiem działania funkcji asynchronicznej. Podobne rezultaty można oczywiście uzyskać używając callbacków, ale obietnice znacznie zwiększają czytelność kodu, pozwalają na "łańcuchowanie" metod oraz ułatwiają obsługę błędów. Znamy je już z takich bibliotek jak jQuery, Bluebird, czy Angulara. Wraz z nadejściem ES6 stają się pełnoprawną częścią języka JavaScript.
Aby zrozumieć skąd wzięła się potrzeba czegoś takiego jak Promises, weźmy pod lupę przykładowy kod napisany z użyciem callbacków:
function getHighestScoringPlayer(gameId) {
getGameById(gameId, function (game) {
getPlayerStats(game, function(stats){
getPoints(stats, function (points) {
//zrób coś
})
})
})
}
Kod ten ma 99 problemów i bycie mało sensownym jest najmniejszym z nich. Prawdziwy problem to Piramida Zagłady (Pyramid of Doom). Widzicie ten trójkąt tworzony przez coraz głębiej wcięte linijki kodu? To właśnie Piramida Zagłady. Wyobraźcie sobie, że zamiast trzech callbacków, jak tutaj, będziecie tworzyć aplikację wymagającą jeszcze większej liczby wywołań, z których każde jest zależne od wyniku poprzedniego. W pewnym momencie Piramida stworzona przez callbacki wyjdzie Wam poza ekran.
Ale to jeszcze pół biedy. Na drugie pół składa się obsługa błędów, która dla powyższego przykładu mogłaby wyglądać tak:
function getHighestScoringPlayer(gameId) {
try{
getGameById(gameId, function (game) {
try {
getPlayerStats(game, function (stats) {
try{
getPoints(stats, function (points) {
//logika
})
} catch(ex){
//obsługa błędu
}
})
} catch (ex){
//obsługa błędu
}
})
} catch(ex){
//obsługa błędu
}
}
Zaczyna to już wyglądać naprawdę niepokojąco, a to dopiero 3 callbacki! I tu właśnie z pomocą przychodzi obiekt Promise.
Obiekt Promise i metoda .then()
Gdy zmodyfikujemy powyższe funkcje w taki sposób, by zamiast używać callbacków, zwracały obiekt Promise, osiągnięcie tego samego rezultatu, jest znacznie prostsze, bardziej czytelne i wygodne:
function getHighestScoringPlayer(gameId) {
getGameById(gameId)
.then(game => getPlayerStats(game))
.then(stats => getPoints(stats))
.then(points => {
//zrób coś
})
.catch(error => {
//obsługa błędu zwróconego przez którykolwiek z promisów
})
}
W jaki sposób zwrócić z funkcji obiekt Promise? Na przykład tak:
function getPlayerStats(game, callback) {
return new Promise((resolve, reject) => {
//nieco asynchronicznego kodu przetwarzającego game na stats
if (stats) {
resolve(stats); //rozwiązanie obietnicy, gdy udało się wyznaczyć stats
}
reject(error) //odrzucenie obietnicy w przeciwnym wypadku
})
}
O Promise'ach napisano już wiele. Były dobrze znane przed nadejściem ES6, a teraz zostały po prostu oficjalnie wciągnięte do języka. Jako, że temat jest dość obszerny, a w internecie jest mnóstwo świetnych materiałów, nie będę czynił z tego wpisu kolejnego tutoriala o Promise'ach. No chyba, że chcielibyście szczegółowego tłumaczenia, bo uznacie te dostępne w necie za niezbyt przystępne, dajcie znać w komentarzach.
Obsługa przez przeglądarki
Jak możecie zobaczyć tutaj, obiekt Promise
jest dziś jednym z najszerzej wspieranych elementów ES6. Już od jakiegoś czasu pełne jego wsparcie mają zarówno Firefox, Chrome jak i Opera, czy nawet większość przeglądarek mobilnych.
Bluebird
Jeśli jesteście jednymi z tych potępionych, który wciąż muszą wspierać prehistoryczne przeglądarki, macie szczęście. Bo choć żadna wersja IE nie wspiera obietnic (dodano to dopiero do Edge), to istnieją fantastyczne biblioteki, które zapewniają pełną obsługę Promise'ów zgodnie ze standardem ES6, rozszerzając ich możliwości o masę przydatnych funkcji. Najważniejszą z tych bibliotek i jedyną, którą tu polecę jest Bluebird.