Wraz z nadejściem jQuery 1.5, programiści otrzymali do swoich rąk szereg funkcjonalności usprawniających pracę z AJAXem. Jedną z nich są obiekty wstrzymane (deferred objects). W dużym skrócie dzięki deferred object możemy przypisać callback do AJAXowego requestu w dowolnym momencie, a nie jak to miało miejsce do tej pory, w momencie tworzenie requestu. Co więcej nie musimy ograniczać się tylko do jednej funkcji zwrotnej.
Jak to się robiło kiedyś…
Przed nastaniem jQuery 1.5 typowy request AJAXowy wyglądał następująco.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.5.js"></script>
<script>
$(document).ready(function() {
$.ajax({
url: "ajax.php",
type: "POST",
success: function(data) {
$("#content").append(data);
}
});
});
</script>
</head>
<body>
<div id="content"></div>
</body>
</html>
W efekcie działania tego nieco uproszczonego przykładu, do diva o identyfikatorze content dodana zostanie zawartość odpowiedzi serwera. Jeśli chcielibyśmy wykonać więcej operacji na zwróconych przez serwer danych oraz uzależnić niektóre operacje od wyniku działania innych funkcji, nieźle byśmy się napocili.
A jak to się robi dziś?
Na szczęście z pomocą przychodzi nam najnowsza odsłona jQuery. W wersji 1.5 opisany powyżej problem rozwiążemy w bardzo prosty sposób
$(document).ready(function() {
var req = $.ajax({
url: "ajax.php",
type: "POST",
success: function(data) {
$("#content").append(data);
}
});
/* dużo innych operacji, które muszą się wykonać niezależnie od AJAXa */
req.success(function(data) {
/* korzystamy z danych przetworzonych powyżej */
// zrób coś z danymi z serwera
$("#content").append(data);
});
});
Drugi callback success wykona się dopiero w momencie, gdy zakończą się operacje znajdujące się bezpośrednio przed nim. Zmienna data zawierać będzie dokładnie te same dane, co w przypadku pierwszej funkcji callback. W podobny sposób możemy dodać callbacki error oraz complete.
Magia?
Obiekty wstrzymane (deferred object) wykorzystują wzorzec Promises/A. Zakłada on istnienie bytu nazwanego obietnicą (promise), który określa potencjalną wartość zwróconą w wyniku działania jakiejś operacji. Obietnica może znajdować się w jedenym z trzech stanów – niespełniona, spełniona, zakończona niepowodzeniem, przy czym zmiana stanu może nastąpić tylko raz: z niespełnionej na spełnioną lub z niespełnionej na zakończoną niepowodzeniem. W momencie gdy obietnica znajdzie się w stanie spełniona lub zakończona błędem, zmiana stanu nie może już mieć miejsca. Dzięki takiemu zachowaniu obietnic, dane zwrócone do callbacka pozostają niezmienne niezależne od miejsca, w którym do tych danych się odwołujemy.
W celu umożliwienia korzystania z wspomnianej przed chwilą funkcjonalności, jQuery zostało wyposażone w obiekt Deferred. To co się dzieje “behind the scenes”, wygląda łudząco podobnie do typowego wywołania metody ajax.
function funkcja1()
{
var dfd = $.Deferred();
dfd.resolve("ok");
return dfd.promise();
}
function funkcja2()
{
var dfd = $.Deferred();
dfd.reject("my bad");
return dfd.promise();
}
$.when(funkcja1(), funkcja2())
.fail(function() {
console.debug("co najmniej jedna funkcja sie wywaliła");
})
.done(function() {
console.debug("wszystkie funkcje są ok");
})
.then(function() {
console.debug("ok");
}, function() {
console.debug("coś poszło nie tak");
});
Powyższy przykład nie jest może zbyt funkcjonalny, ale idealnie pokazuje zasadę działania obiektu Deferred. Metoda when przyjmuje jako argumenty dowolną ilość funkcji, których stan chcemy monitorować. Do obiektu zwróconego przez metodę when dodajemy handlery uruchamiane w momencie gdy wszystkie funkcje zakończą swoje działanie sukcesem (handler dome) lub co najmniej jedna z nich zakończy się niepowodzeniem (fail). Handler then przyjmuje dwa parametry. Pierwszym jest funkcja wykonywana w przypadku sukcesu, drugim funkcja wykonywana w momencie niepowodzenia.
Skąd metoda $.when wie czy monitorowane funkcje zakończyły się sukcesem lub porażką? Informuje ją o tym obiekt Deferred, który zwraca opisaną wcześniej obietnicę. Nim obietnica zostanie zwrócona, należy ustawić jej stan przy pomocy jeden z dwóch metod – resolve dla poprawnego sukcesu oraz reject dla porażki.
Słowo końcowe
Przedstawione powyżej informacje na temat deferred objects to tylko wierzchołek góry lodowej, której cały obraz ujrzycie po lekturze dokumentacji. Warto również zapoznać się z tym wpisem. Znajdziecie w nim szereg interesujących przykładów.
Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...
Zwiń
Czytaj na blogu autora...