等到一个带有动画的函数完成,直到运行另一个函数

IT技术 javascript jquery callback
2021-01-13 05:49:20

我遇到了正常(非 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();

});
6个回答

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

哇哦,现在刚读完这些 Yoshi,好东西!我打算在明天试一试,并尝试使用 .promise。欣赏它!
2021-03-21 05:49:20
是的,我不是指Deferred.promise,而是 jQuery 方法api.jquery.com/promise
2021-03-30 05:49:20
抱歉耽搁了!我终于有机会阅读更多关于延期/完成/Promise/时间等的信息。这些都是完美的!他们从字面上等到所有动画都在设定的事情上完成。when($('whatever')).done() 完美运行!
2021-03-30 05:49:20
正如他所说他使用动画,你可能想提到 jQuery 的.promise()fx 队列方法
2021-04-06 05:49:20
@Bergi 你的意思是 jQuery 从animate? 否则我真的不认为这里需要 promise 对象。
2021-04-10 05:49:20

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

return $.Deferred().resolve();

像这样调用这两个函数

functionOne().done(functionTwo);

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

希望这可以帮助一些人!

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

您可以Deferred通过.promise()动画调用获取jQuery 为动画创建对象将它们包装DeferredsES6 中会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();
});

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

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

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

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

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

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

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

请让我知道我是否遗漏了什么,希望它符合原因 :)

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

代码:

function hulk()
{
  // do some stuff...
}
function simpsons()
{
  // do some stuff...
  hulk();
}
function thor()
{
  // do some stuff...
  simpsons();
}
回调是适当的 JS 答案,IMO。
2021-03-17 05:49:20
我相信这不适用于动画,因为它们一开始往往会延迟工作
2021-04-03 05:49:20
我只有一个函数调用。我无法修改该函数,但我需要在第一个完成后执行我的另一个函数。
2021-04-12 05:49:20