0

This should be simple: I have a 5-second animation, after which I want to .append('Done'). I want to make use of deferrals. I made the function deferred, added a resolve statement (with no argument, so I'm not sure that's needed), and have it returning a promise. But I cannot get the .append to wait for my fader() to execute.

$(document).ready(function () {

  var fader = function () {
   var dfr = new $.Deferred();
    $('#container').fadeOut(2500).fadeIn(2500);
     dfr.resolve();
     return dfr.promise();
  };

/*   fader();

     $('#container').done(function(){   
       $('body').append('Done!');
     });
*/

  fader().done(function(){  
    $('body').append('Done!');
  });

});

Nothing I've tried so far is working for me. What am I doing wrong?

1 Answers1

0

You can simply obtain a promise from the right-hand end of your animation chain, and respond accordingly with .done().

$(document).ready(function () {
    $('#container').fadeOut(2500).fadeIn(2500).promise().done(function() {
        $('body').append('Done!');
    });
});

EDIT

OK, as it stands, your Deferred in the question is resolved immediately after the first animation starts. If you want to do it longhand, just for learning, then you need to resolve your Deferred only when the fadeOut().fadeIn() animations have completed.

For example :

$(document).ready(function () {
    function fader() {
        var dfr = new $.Deferred();
        $('#container').fadeOut(2500).fadeIn(2500).promise().done(function() {
            dfr.resolve();
        });
        //or more concisely
        // $('#container').fadeOut(2500).fadeIn(2500).promise().done(dfr.resolve);
        return dfr.promise();
    };
    fader().done(function() {
        $('body').append('Done!');
    });
);

But this is a bit crazy because creating and resolving your own Deferred is unnecessary when .fadeOut(2500).fadeIn(2500).promise() already generates a resolved promise, which can be returned from fader thus avoiding the socalled "Deferred anti-pattern" :

$(document).ready(function () {
    function fader() {
        return $('#container').fadeOut(2500).fadeIn(2500).promise();
    };
    fader().done(function() {
        $('body').append('Done!');
    });
);

This is functionally identical to the solution in my original answer above, but with the jQuery method chain split into two parts :

  • the first part, $('...').fadeOut(...).fadeIn(...).promise(), inside a function,
  • the second part, .done(function() {...}), chained to the function call.

This is possible because a jQuery method chain (involving or not involving promise) can always be split anywhere along its length, with the result of each part either returned from a function or assigned.

Here it is again with assignment :

var promise = $('#container').fadeOut(2500).fadeIn(2500).promise();

promise.done(function() {
    $('body').append('Done!');
});

Or the Deferred antipattern executed with assignment

var dfr = new $.Deferred();
$('#container').fadeOut(2500).fadeIn(2500).promise().done(dfr.resolve);

var promise = dfr.promise();

promise.done(function() {
    $('body').append('Done!');
});

But please understand, I'm not advocating the anti-pattern.

Roamer-1888
  • 19,138
  • 5
  • 33
  • 44
  • This answers the OP's question, but in this particular case, using promises is more code than just using the completion function from `fadeIn(2500, fn)`. Promises with animations are particularly useful when you're waiting for a bunch of parallel operations to be done, but with only a single animation in this simple a scenario, they are only more code and a couple more function calls. – jfriend00 Jun 15 '14 at 23:03
  • 1
    It's a matter of choice. I tend to do it this way because it's standard promise handling, not some special case. – Roamer-1888 Jun 15 '14 at 23:08
  • Completion functions on jQuery animations are not some special case - not sure what you mean by that. They are present for every animation and ajax function in the toolkit. – jfriend00 Jun 15 '14 at 23:09
  • 1
    Special case is maybe not the best expression. Maybe "shorthand syntax" would be better. – Roamer-1888 Jun 15 '14 at 23:11
  • From OP: Yes, this technically works, but I'm not concerned with code brevity for a simple case. I'm purposefully trying to learn how to use dfr/resolve/return. Ultimately, I want to be able to define a deferred asynchronous function (one more complex than this) as a variable, then call for the execution and what comes after further down in the code (not define-and-execute at the same time). What's confusing me is how to make use of the promise in that case. I'm surprised that fader().done(fn) isn't working, and I've no idea why. – Chris Niestepski Jun 16 '14 at 00:50
  • Thank you, Roamer! I know some of it's not optimum code, but I'm understanding better what's going on. – Chris Niestepski Jun 16 '14 at 02:55