I deferred objects di jQuery ci permettono di spezzare la catena delle animazioni e la loro sequenza in sottoblocchi di codice, ciascuno dotato di un suo scope e di un suo contesto. Il problema che sorge usando l'oggetto Deferred
e il metodo pipe()
è che tutte le animazioni partono insieme. Questo è normale se si considera che i deferred objects lavorano su blocchi di codice indipendenti in cui ciascun blocco è svincolato dall'altro. Per capire come risolvere il problema è necessario capire come funzionano le animazioni in sequenza in jQuery.
La catena di animazioni
Osserviamo questo codice:
var animation = function() {
$('.a1').animate({
left: 650
}, 1000, function() {
$('.a2').animate({
left: 650
}, 1000, function() {
$('.a3').animate({
left: 650
}, 1000);
});
});
};
Le animazioni partiranno una dopo l'altra perchè formano una catena che opererà in sequenza. Infatti jQuery non solo creerà una coda di animazioni, ma permetterà ad altre animazioni di aggiungersi alla coda utilizzando la funzione di callback del metodo animate()
.
Il valore numerico della velocità indica anche la durata dell'animazione. Per questo motivo la funzione di callback verrà eseguita solo quando l'animazione avrà esaurito la sua durata (in millisecondi).
L'effetto in sequenza è appunto dato dal fatto che ciascuna animazione verrà di fatto eseguita solo quando l'animazione precedente è terminata.
Usare i deferred objects
I deferred objects sono stati creati allo scopo di avere la funzionalità di threading in jQuery. In altre parole, questi oggetti sono concepiti per gestire qualsiasi tipo di codice, mentre i metodi visti prima servono solo per gestire le animazioni.
Quindi i deferred objects possono essere anche applicati alle animazioni, ma non sono specifici delle animazioni. Osserviamo questo esempio:
var animation = function() {
$.Deferred(function(def) {
def.pipe(function() {
return $('.a1').animate({
left: 650
}, 1000);
}).pipe(function() {
return $('.a2').animate({
left: 650
}, 1000);
}).pipe(function() {
return $('.a3').animate({
left: 650
}, 1000);
});
}).resolve();
};
Se eseguite questo codice, non vedrete tre animazioni in sequenza ma tre animazioni simultanee. Questo perchè ciascuna animazione non è a conoscenza dello stato dell'altra, nè della sua durata, nè tantomeno può sfruttare la funzione di callback vista in precedenza.
Per risolvere il problema dobbiamo ritardare l'esecuzione di un'animazione per il tempo necessario affinchè l'animazione che la precede sia conclusa. Utilizziamo setTimeout()
per questo scopo:
var animation = function() {
$.Deferred(function(def) {
def.pipe(function() {
return $('.a1').animate({
left: 650
}, 1000);
}).pipe(function() {
return setTimeout(function() {
$('.a2').animate({
left: 650
}, 1000);
}, 1000);
}).pipe(function() {
return setTimeout(function() {
$('.a3').animate({
left: 650
}, 1000);
}, 2000);
});
}).resolve();
};
Potete visionare l'esempio finale in questa pagina.