Pergunta

I've found a lot of questions about deferring, promises, running javascript synchronously, etc. and I've tried numerous things already but still can't get this to work.

Edit Here's a little more explanation on the problem. fetchData has a routine that depends on all the code inside showStuff being complete. In particular, there's divs that get created using percentage of screen size, and we need to get the height of those divs so we can draw gauges inside them. fetchData is running before slideDown() is complete. Please see the additional console.log code I've added directly below.

My button onClick() calls showOverlay().

function showOverlay() {
    showStuff().promise().done( function() {
        console.log($("#gauge1").height()); //returns -0.5625 or something close
        fetchData(); //ajax call
    });
}

function showStuff() {
    $("#overlay").fadeIn(200);
    $("#gauges").slideDown(800);
    $(".gauge").each(function() {
        $( this ).show(); //unhides #gauge1 div
    });         
}

The error I'm getting says: cannot call method 'promise' of undefined.

I'm not showing my fetchData() function but it basically uses ajax to call a web service and then creates gauges on the screen using Raphael. If fetchData runs before the animations are complete the gauges are not displayed correctly because their size is relative to the .gauge div's.

Edit1

Neither of the examples below work. They both run without errors but return too quickly.

function showOverlay() {
    showStuff().promise().done(function() {
        fetchData();
    });  
}

function showStuff() {
    var def = $.Deferred();
    $("#overlay").fadeIn(200);
    $("#gauges").slideDown(800);
    $(".gauge").each(function() {
        $( this ).show();
    });
    def.resolve();
    return def;
}

Doesn't work either:

function showOverlay() {
    $.when(showStuff()).done(function() {
           fetchData();
       });
}

function showStuff() {
    $("#overlay").fadeIn(200);
    $("#gauges").slideDown(800);
    $(".gauge").each(function() {
        $( this ).show();
    });         
}
Foi útil?

Solução

You've 2 issues, the deferred and thats not how you run animations one after the other.

This will get you part of the way:

function showStuff() {
  var deferred = $.Deferred();
  $("#overlay").fadeIn(300,function(){
    $("#gauges").slideDown(800,function(){
      $(".gauge").show(); //doing this one after another takes more code.
      deferred.resolve();
    });
  });

  return deferred;
}

Heres the codepen: http://codepen.io/krismeister/pen/pvgKj

If you need to do sophisticated animations like this. You might find better results with GSAP. Heres how to stagger: http://www.greensock.com/jump-start-js/#stagger

Outras dicas

Try to use $.when() instead:

$.when(showStuff()).done(function() {
    fetchData();
});    

You a) need to return something from showStuff b) should return a promise directly, so that the .promise() method is unnecessary:

function showOverlay() {
    showStuff().done(function() {
        fetchData();
    });  
}

function showStuff() {
    return $("#overlay").fadeIn(200).promise().then(function() {
        return $("#gauges").slideDown(800).promise();
    }).then(function() {
        return $(".gauge").show().promise();
    });
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top