Обратный вызов .animate() вызывается дважды jquery

Так как я добавил некоторую scrollTop -анимацию, некоторые части моего обратного вызова вызываются дважды:

$('html, body').animate({scrollTop: '0px'}, 300,function() {
    $('#content').load(window.location.href, postdata, function() {                 
        $('#step2').addClass('stepactive').hide().fadeIn(700, function() {
            $('#content').show('slide',800);                    
        });
    });
});

Кажется, повторяется только .show(), по крайней мере, у меня нет впечатления, что вызов load() или .fadeIn() вызывает второй раз. .show() будет повторяться, как только он будет завершен в первый раз. Установка скорости анимации scrollTop на 0 не помогла, кстати!

Я предполагаю, что это как-то связано с очередью анимации, но я не могу понять, как найти обходной путь и, особенно, почему это происходит.

Ответ 1

animate вызывает свой обратный вызов один раз для каждого элемента в наборе, который вы вызываете animate on:

Если он поставляется, вызовы start, step, progress, complete, done, fail и always вызываются на основе каждого элемента...

Поскольку вы анималируете два элемента (элемент html и элемент body), вы получаете два обратных вызова. (Для тех, кто задается вопросом, почему OP оживляет два элемента, это потому, что анимация работает на body на некоторых браузерах, но на html на других браузерах.)

Чтобы получить один обратный вызов, когда анимация завершена, документы animate указывают на использование метода promise, чтобы получить обещание очереди анимации, а затем then для очереди обратного вызова:

$("html, body").animate(/*...*/)
    .promise().then(function() {
        // Animation complete
    });

(Примечание: Кевин Б указал на это в своем ответе, когда вопрос был задан впервые. Я не делал этого четыре года спустя, когда заметил, что он отсутствует, добавив его, и... затем увидел, что Кевин отвечает. Пожалуйста, дайте ему ответ, которого он заслуживает. Я понял, что это принятый ответ, я должен оставить его.)

Здесь показан пример, показывающий обратные вызовы отдельных элементов и общий обратный вызов завершения:

jQuery(function($) {

  $("#one, #two").animate({
    marginLeft: "30em"
  }, function() {
    // Called per element
    display("Done animating " + this.id);
  }).promise().then(function() {
    // Called when the animation in total is complete
    display("Done with animation");
  });

  function display(msg) {
    $("<p>").html(msg).appendTo(document.body);
  }
});
<div id="one">I'm one</div>
<div id="two">I'm two</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

Ответ 2

Чтобы получить один обратный вызов для завершения нескольких анимаций элементов, используйте отложенные объекты.

$(".myClass").animate({
  marginLeft: "30em"
}).promise().done(function(){
  alert("Done animating");
});

См. API jQuery для подробного описания обещаний и отложенных объектов.