等待带有动画的功能完成,直到运行另一个功能


70

我在正常(非ajax)函数中遇到了问题,每个函数中都包含很多动画。目前,我只是具有一个setTimeoutbetween函数,但这并不是完美的,因为没有浏览器/计算机是相同的。

附加说明:它们都有碰撞的单独动画/等。

我不能简单地将一个放在另一个的回调函数中

// 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有一个名为$ .timers的暴露变量(由于某种原因未在jQuery文档中的任何地方列出),该变量保存当前发生的动画数组。

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();

});

2
如果FunctionOne没有超时或其他任何时间,您可以致电FunctionOne(); FunctionTwo();,不是吗?
Waleed Khan 2012年

问题在于它们在不同的文件中都有各自独立的动画/等,因此它们最终会发生冲突……
Mark Pieszak-Trilon.io 2012年

3
$.when$.done不一定只是阿贾克斯。如果要在关闭FunctionTwo之前完成在FunctionOne中完成的各种异步任务,则可以创建Deferred对象,将它们放入数组中,resolve()在操作完成后调用每个对象,然后执行$.when.apply($, array).then(function(){...});
MrOBrian

1
全局变量是邪恶的,但在这种情况下,仅添加一个标志可能是值得的isRunning
ajax333221

1
您保存了我的应用,我永远感激
Dagrooms 2015年

Answers:


109

您可以使用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's 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/


正如他所说的,他使用的动画,你可能想提jQuery的.promise()的FX队列方法
BERGI

@Bergi您的意思是jQuery从中返回一个延迟对象animate?否则我在这里真的看不到对promise对象的需求。
Yoshi 2012年

是的,我的意思不是Deferred.promise,而是jQuery方法api.jquery.com/promise
Bergi,2012年

哇,哇,现在才读完所有这些,好东西!我要给它们一个明天,并尝试与.promise一起搞乱。赞赏!
Mark Pieszak-Trilon.io,2012年

1
抱歉耽搁了!我终于有机会阅读有关延期/完成/承诺/何时等的更多信息。这些都是完美的!他们实际上要等到所有动画都完成后再进行设置。when($('whatever'))。done()完美!
Mark Pieszak-Trilon.io 2012年

13

在第一个函数的末尾添加以下内容

return $.Deferred().resolve();

像这样调用两个函数

functionOne().done(functionTwo);

3

除了Yoshi的答案,我还找到了另一个非常简单的动画(回调类型)解决方案。

jQuery有一个名为$ .timers的暴露变量(由于某种原因未在jQuery文档中的任何地方列出),该变量保存当前发生的动画数组。

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);

希望这可以帮助一些人!


1

这是男人的意思吗:http : //jsfiddle.net/LF75a/

您将有一个函数触发下一个函数,依此类推,即添加另一个函数调用,然后functionONe在其底部添加您的函数。

请让我知道如果我错过了任何事情,希望它适合这个原因 :)

这样:在上一个功能完成后调用一个功能

码:

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

5
回调是适当的JS答案IMO。
MalSu 2012年

我所拥有的只是一个函数调用。我无法修改该功能,但是在第一个完成后我需要执行其他功能。
Qwerty 2014年

我认为这不适用于动画,因为动画一开始往往会有所延迟
Muhammad Nour 2014年

1

该答案使用promises,是ECMAScript 6标准的JavaScript功能。如果您的目标平台不支持promises,请用PromiseJs填充

您可以在动画调用中Deferred使用jQuery为动画创建的对象.promise()。将它们包装DeferredsES6Promises中可以比使用计时器产生更简洁的代码。

您也可以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();
});

注意,函数inPromise.all()返回诺言。这就是魔术发生的地方。如果在then调用中返回了承诺,则下一个then调用将在执行之前等待该承诺被解决。

jQuery为每个元素使用一个动画队列。因此,同一元素上的动画将同步执行。在这种情况下,您根本不必使用诺言!

我禁用了jQuery动画队列,以演示如何与promises一起工作。

Promise.all()接受一个promise数组并创建一个新Promise的数组,该数组在数组中的所有promise完成后才能完成。

Promise.race()也需要一系列承诺,但要在第一个承诺完成后立即Promise完成。


1

ECMAScript 6更新

这使用了JavaScript的一项新功能,即Promises

functionOne()。then(functionTwo);


0

您可以通过回调函数来实现。

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

函数function1(param,callback){...做东西callback(); }


0

这是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);

0

您可以使用javascriptPromiseasync/await实现函数的同步调用。

假设您要以n同步方式执行存储在数组中的多个函数,这是我的解决方案。

async function executeActionQueue(funArray) {
  var length = funArray.length;
  for(var i = 0; i < length; i++) {
    await executeFun(funArray[i]);
  }
};

function executeFun(fun) {
  return new Promise((resolve, reject) => {
    
    // Execute required function here
    
    fun()
      .then((data) => {
        // do required with data 
        resolve(true);
      })
      .catch((error) => {
      // handle error
        resolve(true);
      });
  })
};

executeActionQueue(funArray);

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.