There seems to be a very common misconception that promise functions like jQuery.when()
contain some magical power that they can just "know" when some other function is done. Let me dispell that myth right now. They don't have any magical power. jQuery.when()
ONLY takes promises as it's arguments and the reason it requires promises is because those promises will tell jQuery.when()
when they are done. When you pass some other type of object to jQuery.when()
that isn't a promise, it quite simply has no idea when that other thing is done. It will treat it as a synchronous function that is done as soon as it runs, but if it's not a synchronous function or not a function at all, then jQuery.when()
won't do what you want it to.
Rule #1 - You MUST pass promises to jQuery.when()
. You aren't doing that. You're passing this
to it which is probably the window
object. That won't do you any good and jQuery.when()
will just resolve immediately, not waiting for anything to finish.
Rule #2 - Promises ONLY work if you write code that resolves or rejects the promise when the asynchronous task is done. Again, there's no magic here. You have to tell the promise when the async task is done. Only then, can the promise do what it's supposed to and make things like .then()
handlers work. You have several async operations in your DisplayHdline()
function, but you aren't creating a promise or resolving that promise and you aren't keeping track of when all the async operations in that function are done.
Rule #3 - If your underlying framework/infrastructure supports promises and will resolve them for you when operations are done, then by all means use that rather than creating your own promises. In your case, jQuery animations will already create and resolve their own promises. You will want to use that here.
So, if the extent of your problem here is that you want to know when all the animations in DisplayHdline()
are done, you can leverage jQuery to help you know that and you can return a promise from that function like this:
function DisplayHdline() {
var str = "HELP STOP CRUELTY NOW.";
var spans = '<span>' + str.split(/\s+/).join(' </span><span>') + '</span>';
return jQuery(spans).hide().appendTo('#vidheadline').each(function(i) {
jQuery(this).delay(2000 * i).fadeIn('fast').delay(1000).fadeOut(50);
}).promise();
}
Then, you can call it and know when it's done like this:
DisplayHdline().done(function() {
// code here to execute when everything in DisplayHdline is done
});
Note that I changed the structure of your code to not pass a callback to DisplayHdline()
because this structure is much more flexible. When you return the promise, you can always just add a .done()
handler like I've done and it will work like the callback, but you can also do many other things such as chain other actions onto this or combine it with other operations and wait for multiple promises to be done before doing something else, etc... This is the beauty of a standard promise interface as it allows many different types of handling without having to know the internals of the operation.
What jQuery is doing for you here is actually saving you a lot of work. When you do .promise()
on a collection that all has animation going on it, jQuery returns to you a single promise that gets resolved when all the underlying object's promises have been resolved, saving you the work of keep track of all of them. It's actually quite useful in this way.