【问题标题】:Wait till a Function with animations is finished until running another Function等到一个带有动画的函数完成,直到运行另一个函数
【发布时间】:2012-08-20 10:29:43
【问题描述】:

我遇到了正常(非 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 有一个名为 $.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();

});

【问题讨论】:

  • 如果FunctionOne 没有超时或其他任何事情,你可以打电话给FunctionOne(); FunctionTwo();,不是吗?
  • 问题是它们都有单独的动画/等,在不同的文件中 - 等等。所以他们最终会发生碰撞......
  • $.when$.done 不一定只适用于 ajax。如果您希望在启动 FunctionTwo 之前在 FunctionOne 中完成各种异步任务,您可以创建 Deferred 对象,将它们放在一个数组中,在操作完成时对每个对象调用 resolve(),然后执行 @987654334 @
  • 全局变量是邪恶的,但在这种情况下,可能只需添加一个 isRunning 标志即可。
  • 您保存了我的应用程序,我永远感激不尽

标签: javascript jquery callback


【解决方案1】:

您可以使用javascript Promiseasync/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);

【讨论】:

    【解决方案2】:

    ECMAScript 6 更新

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

    functionOne().then(functionTwo);

    【讨论】:

      【解决方案3】:

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

      您可以在动画调用上使用.promise() 获取jQuery 为动画创建的Deferred 对象。将这些 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 调用中返回了一个 Promise,则下一个 then 调用将等待该 Promise 解决后再执行。

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

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

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

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

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          【解决方案5】:

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

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

          函数function1(参数,回调){ ...做东西 打回来(); }

          【讨论】:

            【解决方案6】:

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

            return $.Deferred().resolve();
            

            像这样调用这两个函数

            functionOne().done(functionTwo);
            

            【讨论】:

              【解决方案7】:

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

              希望这可以帮助一些人!

              【讨论】:

                【解决方案8】:

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

                你也可以将多个 deferred 打包在一起:

                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 你的意思是jQuery从animate返回一个延迟对象?因为否则我真的看不出这里需要 promise 对象。
                • 是的,我说的不是Deferred.promise,而是jQuery方法api.jquery.com/promise
                • 哦,哇,现在才读到这一切 Yoshi,好东西!我打算试试这些 - 明天,并尝试弄乱 .promise 以及。欣赏!
                • 抱歉耽搁了!我终于有机会阅读更多关于延迟/完成/承诺/何时等的信息。这些都是完美的!他们实际上是等到所有动画都在一组东西上完成。 when($('whatever')).done() 完美!
                【解决方案9】:

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

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

                如果我遗漏了什么,请告诉我,希望它符合原因:)

                这个:Call a function after previous function is complete

                代码:

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

                【讨论】:

                • 回调是合适的 JS 答案,IMO。
                • 我只有一个函数调用。我无法修改该功能,但我需要在第一次完成后执行我的其他功能。
                • 我相信这不适用于动画,因为它们往往会延迟工作
                猜你喜欢
                • 1970-01-01
                • 2019-11-14
                • 1970-01-01
                • 2014-08-30
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2022-01-02
                • 1970-01-01
                相关资源
                最近更新 更多