Reputation: 19713
Having a few teething problems with $.deferred
, $.when
and $.done
.
I'm calling a method which has a couple of tasks inside on a timer. I'm looking at getting a callback when everything inside this method has completed, including the stuff in timers, so started looking at $.when()
and $.done()
to achieve this.
The problem I am getting is the function is firing before the tasks have completed, immediately as the method is called. So, I started playing with $.deferred
and resolve()
, but haven't managed to get anything working. Without the timers, I can do it.
This is where I call the method:
$.when(cover.start()).done(function() {
console.log("Cover has started.");
});
This is the entire method:
return {
other: function() {},
start: function() {
var dfd = $.Deferred();
el.filter.animate({
"opacity": "0.6", "filter": "alpha(opacity=60)"
}, 2000, "easeInOutCirc", function() {
el.share.removeClass('fa-spin');
setTimeout(function() {
el.share.removeClass('fa-cog').addClass('fa-bars');
},1000);
setTimeout(function() {
el.scroll.animate({
"opacity": "1",
"bottom": "40px"
}, 1200, "easeOutBounce", function() {
var pulseOptions = { opacity: "0" };
setTimeout(function() {
el.scroll.pulse(pulseOptions, {
duration : 400,
pulses: 3,
interval: 500,
returnDelay: 800
});
}, 2000);
dfd.resolve();
});
}, 2000);
return dfd.promise();
});
}
} // end return
As you can see, after my original attempt failed, I added dfd.resolve()
to where I want the callback and tried to return the promise. However, the function still fires too early. Where am I going wrong?
Upvotes: 0
Views: 181
Reputation: 19288
Not fishing to steal APJ's rep' but out of interest, you could avoid callback hell by exploiting .delay()
and .promise()
, both of which relate to the default "fx" animation queue.
Something along the following lines would fix the problem, and would be more readable :
//animation maps
var maps = [];
maps[0] = { 'opacity':0.6, 'filter':'alpha(opacity=60)' };
maps[1] = { 'opacity':1, 'bottom':'40px' };
maps[2] = { 'opacity':0 };
maps[3] = { 'duration':400, 'pulses':3, 'interval':500, 'returnDelay':800 };
//animation functions
var f = [];
f[0] = function () {
return el.filter.animate(maps[0], 2000, "easeInOutCirc").promise();
};
f[1] = function () {
return el.share.removeClass('fa-spin').delay(1000).promise();
};
f[2] = function () {
return el.share.removeClass('fa-cog').addClass('fa-bars').delay(1000).promise();
};
f[3] = function () {
el.scroll.animate(maps[1], 1200, "easeOutBounce").promise();
}
f[4] = function () {
return el.scroll.delay(2000).promise();//delay() could be called on any element. `el.scroll` is arbitrary.
};
f[5] = function () {
el.scroll.pulse(maps[2], maps[3]);
};
return {
other: function () {},
start: function () {
//animation sequence
var p = f[0]().then(f[1]).then(f[2]).then(f[3]);
p.then(f[4]).then(f[5]);
return p;//<<<< and here's the all important return
}
}
Not sure this is 100% correct - might need some work.
It's worth noting that there are performance pros and cons with this approach :
Upvotes: 1
Reputation: 388316
The problem is, you need to return promise
from the start method
return {
other: function () {},
start: function () {
var dfd = $.Deferred();
el.filter.animate({
"opacity": "0.6",
"filter": "alpha(opacity=60)"
}, 2000, "easeInOutCirc", function () {
el.share.removeClass('fa-spin');
setTimeout(function () {
el.share.removeClass('fa-cog').addClass('fa-bars');
}, 1000);
setTimeout(function () {
el.scroll.animate({
"opacity": "1",
"bottom": "40px"
}, 1200, "easeOutBounce", function () {
var pulseOptions = {
opacity: "0"
};
setTimeout(function () {
el.scroll.pulse(pulseOptions, {
duration: 400,
pulses: 3,
interval: 500,
returnDelay: 800
});
}, 2000);
dfd.resolve();
});
}, 2000);
});
//need to return from start
return dfd.promise();
}
} // end return
Upvotes: 4