70

我遇到了正常(非 ajax)函数的问题,每个函数都包含大量动画。目前我只是有一个setTimeout功能之间,但这并不完美,因为没有浏览器/计算机是相同的。

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

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

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

});
4

9 回答 9

110

你可以使用 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/

于 2012-08-27T10:20:46.950 回答
13

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

return $.Deferred().resolve();

像这样调用这两个函数

functionOne().done(functionTwo);
于 2014-08-21T15:29:42.033 回答
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);

希望这可以帮助一些人!

于 2013-07-24T02:47:14.813 回答
2

这个答案使用标准promises的 JavaScript 特性ECMAScript 6。如果您的目标平台不支持promises,请使用 PromiseJs 对其进行polyfill

您可以在动画调用中获取DeferredjQuery 为动画创建的对象。.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();
});

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

jQuery 为每个元素使用一个动画队列。所以同一元素上的动画是同步执行的。在这种情况下,您根本不必使用 Promise!

我禁用了 jQuery 动画队列来演示它如何与 Promise 一起工作。

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

Promise.race()还接受一系列承诺,但在第一个完成后立即Promise完成。

于 2015-09-23T06:52:44.963 回答
1

这就是你的意思吗:http: //jsfiddle.net/LF75a/

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

如果我错过了什么,请让我知道,希望它适合原因:)

或者这个:在前一个函数完成后调用一个函数

代码:

function hulk()
{
  // do some stuff...
}
function simpsons()
{
  // do some stuff...
  hulk();
}
function thor()
{
  // do some stuff...
  simpsons();
}
于 2012-08-24T20:59:07.223 回答
1

ECMAScript 6 更新

这使用了 JavaScript 的一个新特性,称为 Promises

functionOne().then(functionTwo);

于 2016-03-30T19:45:54.977 回答
0

您可以通过回调函数来完成。

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

function function1(param, callback) { ...做一些事情 callback(); }

于 2015-03-04T06:21:02.257 回答
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);
于 2015-08-18T12:28:14.667 回答
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);

于 2018-10-19T05:09:14.327 回答