Подождите, пока функция с анимацией будет закончена, пока не будет запущена другая функция

У меня проблема с нормальными (не-ajax) функциями, которые включают в себя множество анимаций внутри каждого из них. В настоящее время у меня просто есть функция setTimeout между функциями, но это не идеально, поскольку ни один браузер/компьютеры не совпадают.

Дополнительное примечание: у обоих есть отдельные анимации /etc, которые сталкиваются.

Я не могу просто поместить его в функцию обратного вызова другого

// multiple dom animations / etc
FunctionOne();

// What I -was- doing to wait till running the next function filled
// with animations, etc

setTimeout(function () { 
    FunctionTwo(); // other dom animations (some triggering on previous ones)
}, 1000); 

В любом случае в js/jQuery есть:

// Pseudo-code
-do FunctionOne()
-when finished :: run -> FunctionTwo()

Я знаю о $.when() и $.done(), но это для AJAX...


  • МОЕ ОБНОВЛЕННОЕ РЕШЕНИЕ

jQuery имеет открытую переменную (которая по некоторым причинам не указана нигде в документах jQuery), называемая $.timers, которая содержит массив анимаций, которые в настоящее время происходят.

function animationsTest (callback) {
    // Test if ANY/ALL page animations are currently active

    var testAnimationInterval = setInterval(function () {
        if (! $.timers.length) { // any page animations finished
            clearInterval(testAnimationInterval);
            callback();
        }
    }, 25);
};

Основное использование:

// run some function with animations etc    
functionWithAnimations();

animationsTest(function () { // <-- this will run once all the above animations are finished

    // your callback (things to do after all animations are done)
    runNextAnimations();

});

Ответ 1

Вы можете использовать jQuery $.Deferred

var FunctionOne = function () {
  // create a deferred object
  var r = $.Deferred();

  // do whatever you want (e.g. ajax/animations other asyc tasks)

  setTimeout(function () {
    // and call `resolve` on the deferred object, once you're done
    r.resolve();
  }, 2500);

  // return the deferred object
  return r;
};

// define FunctionTwo as needed
var FunctionTwo = function () {
  console.log('FunctionTwo');
};

// call FunctionOne and use the `done` method
// with `FunctionTwo` as it parameter
FunctionOne().done(FunctionTwo);

вы также можете упаковать несколько отложенных дней вместе:

var FunctionOne = function () {
  var
    a = $.Deferred(),
    b = $.Deferred();

  // some fake asyc task
  setTimeout(function () {
    console.log('a done');
    a.resolve();
  }, Math.random() * 4000);

  // some other fake asyc task
  setTimeout(function () {
    console.log('b done');
    b.resolve();
  }, Math.random() * 4000);

  return $.Deferred(function (def) {
    $.when(a, b).done(function () {
      def.resolve();
    });
  });
};

http://jsfiddle.net/p22dK/

Ответ 2

добавьте следующее в конец первой функции

return $.Deferred().resolve();

вызовите обе функции, такие как

functionOne().done(functionTwo);

Ответ 3

Наряду с ответом Yoshi я нашел еще одно очень простое (обратное) решение для анимации.

jQuery имеет открытую переменную (которая по какой-либо причине не указана нигде в документах jQuery), называемая $. timers, которая содержит массив анимаций, которые в настоящее время происходят.

function animationsTest (callback) {
    // Test if ANY/ALL page animations are currently active

    var testAnimationInterval = setInterval(function () {
        if (! $.timers.length) { // any page animations finished
            clearInterval(testAnimationInterval);
            callback();
        }
    }, 25);
};

Основное использование:

functionOne(); // one with animations

animationsTest(functionTwo);

Надеюсь, это поможет некоторым людям!

Ответ 4

Это то, что вы имеете в виду человека: http://jsfiddle.net/LF75a/

У вас будет одна функция для запуска следующей функции и т.д., т.е. добавить другой вызов функции, а затем добавить свой functionONe в нижней части.

Пожалуйста, дайте мне знать, не пропустил ли я что-нибудь, надеюсь, что он подходит к делу :)

или: Вызвать функцию после завершения предыдущей функции

Код:

function hulk()
{
  // do some stuff...
}
function simpsons()
{
  // do some stuff...
  hulk();
}
function thor()
{
  // do some stuff...
  simpsons();
}

Ответ 5

В этом ответе используется promises, функция JavaScript стандарта ECMAScript 6. Если ваша целевая платформа не поддерживает promises, polyfill с PromiseJs.

Вы можете получить объект jQuery объекта Deferred для анимации, используя .promise() в вызове анимации. Объединение этих Deferreds в ES6 promises приводит к значительно более чистому коду, чем к использованию таймеров.

Вы также можете использовать Deferreds напрямую, но это обычно не рекомендуется, потому что они не соответствуют спецификации Promises/A +.

Полученный код будет выглядеть так:

var p1 = Promise.resolve($('#Content').animate({ opacity: 0.5 }, { duration: 500, queue: false }).promise());
var p2 = Promise.resolve($('#Content').animate({ marginLeft: "-100px" }, { duration: 2000, queue: false }).promise());
Promise.all([p1, p2]).then(function () {
    return $('#Content').animate({ width: 0 }, { duration: 500, queue: false }).promise();
});

Обратите внимание, что функция из Promise.all() возвращает обещание. Здесь происходит волшебство. Если в вызове then возвращается обещание, следующий вызов then будет ждать, пока это обещание будет разрешено до выполнения.

jQuery использует очередь анимации для каждого элемента. Таким образом, анимации одного и того же элемента выполняются синхронно. В этом случае вам вообще не придется использовать promises!

Я отключил очередь анимации jQuery, чтобы продемонстрировать, как она будет работать с promises.

Promise.all() принимает массив promises и создает новый Promise, который заканчивается после завершения promises в массиве.

Promise.race() также принимает массив promises, но заканчивается, как только заканчивается первый Promise.

Ответ 6

ОБНОВЛЕНИЕ ECMAScript 6

Это использует новую функцию JavaScript под названием Promises

functionOne(), а затем (functionTwo);.

Ответ 7

Вы можете сделать это через функцию обратного вызова.

$('a.button').click(function(){
    if (condition == 'true'){
        function1(someVariable, function() {
          function2(someOtherVariable);
        });
    }
    else {
        doThis(someVariable);
    }
});

function function1 (param, callback) {... делать вещи Перезвони(); }

Ответ 8

Вот решение для n-вызовов (рекурсивная функция). https://jsfiddle.net/mathew11/5f3mu0f4/7/

function myFunction(array){
var r = $.Deferred();

if(array.length == 0){
    r.resolve();
    return r;
}

var element = array.shift();
// async task 
timer = setTimeout(function(){
    $("a").text($("a").text()+ " " + element);
    var resolving = function(){
        r.resolve();
    }

    myFunction(array).done(resolving);

 }, 500);

return r;
}

//Starting the function
var myArray = ["Hi", "that's", "just", "a", "test"];
var alerting = function (){window.alert("finished!")};
myFunction(myArray).done(alerting);