javascript - 在多个 setInterval 函数完成时执行代码

标签 javascript html multithreading css css-animations

大家好,提前感谢您的宝贵时间!

我正在处理一个涉及同步 CSS3 动画的网站。我正在使用 setInterval() 调用来运行动画。我正在寻找在动画结束后调用函数的最佳方式。

下面的代码只是解释我的问题的通用示例。当您按下开始按钮时,将调用三个 setInterval() 函数。一个是平移动画,一个是缩放动画,最后一个是旋转动画。我的问题的本质是,我怎样才能运行一些代码——为了争论,我们说 console.log("We Did IT!"); - 当调用最后一个 clearInterval() 时。

我可以想象一个 bool 网络跟踪哪些动画已经完成并在抛出所有标志时调用代码,但我希望在这里可以找到更优雅的解决方案。

再次感谢!

//Global Variable Declarations
var adc = adc || {};
adc.tWrap = document.createElement('div');
adc.sWrap = document.createElement('div');
adc.rWrap = document.createElement('div');
adc.btn = document.createElement('button');

//Style Objects, Append to Body, Apply Listeners
adc.init = function() {
  adc.setDiv(adc.tWrap, "transform wrap", 22, 22, 200, 200, 1, "");
  adc.setDiv(adc.sWrap, "scale wrap", 22, 22, 150, 150, 2, "", "");
  adc.setDiv(adc.rWrap, "rotate wrap", 22, 22, 100, 100, 3, "yellow");

  adc.setBtn(adc.btn, "start btn", 25, 25, 50, 50, "Start");
  var body = document.getElementsByTagName('body');
  body[0].appendChild(adc.tWrap);
  adc.tWrap.appendChild(adc.sWrap);
  adc.sWrap.appendChild(adc.rWrap);
  adc.rWrap.appendChild(adc.btn);

  adc.btn.addEventListener('click', adc.click, true);
}
adc.setDiv = function(a, id, T, L, H, W, z, bg) {
  a.id = id;
  a.style.position = 'absolute';
  a.style.top = T + "px";
  a.style.left = L + "px";
  a.style.height = H + "px";
  a.style.width = W + "px";
  a.style.zIndex = z;
  a.style.borderWidth = "3px";
  a.style.borderStyle = "solid";
  a.style.backgroundColor = bg;
}
adc.setBtn = function(a, id, T, L, H, W, txt) {
  a.id = id;
  a.type = "button";
  a.textContent = txt;
  a.style.position = 'absolute';
  a.style.top = T + "px";
  a.style.left = L + "px";
  a.style.height = H + "px";
  a.style.width = W + "px";
}

//Event Listener
adc.click = function() {
  if (!adc.animate.runLock()) {
    adc.animate.trans.start();
    adc.animate.scale.start();
    adc.animate.rotate.start();
  }
}

//Animation Routines (setInterval calls)
adc.animate = {
  runLock: function() {
    if (adc.animate.trans.run == 0 && adc.animate.scale.run == 0 && adc.animate.rotate.run == 0) {
      return false;
    } else {
      return true;
    }
  },
  trans: {
    run: 0,
    count: 0,
    flag: false,
    start: function() {
      this.run = setInterval(function() {
        adc.animate.trans.EXE()
      }, 10);
    },
    stop: function() {
      clearInterval(this.run);
      this.run = this.count = 0;
      this.flag = false;
    },
    EXE: function() {
      if (!this.flag) {
        this.count += 0.5;
      } else {
        this.count -= 0.5;
      }
      if (this.count >= 45) {
        this.flag = true;
      }
      adc.tWrap.style.transform = "translateX(" + this.count + "px)";
      if (this.count <= 0) {
        this.stop();
      }
    }
  },
  scale: {
    run: 0,
    count: 1,
    flag: false,
    start: function() {
      this.run = setInterval(function() {
        adc.animate.scale.EXE()
      }, 10);
    },
    stop: function() {
      clearInterval(this.run);
      this.run = 0;
      this.count = 1;
      this.flag = false;
    },
    EXE: function() {
      if (!this.flag) {
        this.count += 0.01;
      } else {
        this.count -= 0.01;
      }
      if (this.count >= 1.9) {
        this.flag = true;
      }
      adc.sWrap.style.transform = "scale(" + this.count + ")";
      if (this.count <= 1) {
        this.stop();
      }
    }
  },
  rotate: {
    run: 0,
    count: 0,
    flag: false,
    start: function() {
      this.run = setInterval(function() {
        adc.animate.rotate.EXE()
      }, 10);
    },
    stop: function() {
      clearInterval(this.run);
      this.run = this.count = 0;
      this.flag = false;
    },
    EXE: function() {
      if (!this.flag) {
        this.count++;
      } else {
        this.count--;
      }
      if (this.count >= 90) {
        this.flag = true;
      }
      adc.rWrap.style.transform = "rotate(" + this.count + "deg)";
      if (this.count <= 0) {
        this.stop();
      }
    }
  }
}

//Initialization Call
document.addEventListener('DOMContentLoaded', function() {
  adc.init();
});
<!DOCTYPE html>
<html>

<head></head>

<body></body>

</html>

最佳答案

Lo-Dash 有一个方便的函数,叫做 _.after在一定次数的调用后执行给定的函数。例如,以下函数仅在所有超时完成后执行。

var finish = _.after(5, function () {
  console.log('All functions completed!');
});

setTimeout(function () { console.log('A'); finish(); },  500);
setTimeout(function () { console.log('B'); finish(); }, 1000);
setTimeout(function () { console.log('C'); finish(); }, 1500);
setTimeout(function () { console.log('D'); finish(); }, 2000);
setTimeout(function () { console.log('E'); finish(); }, 2500);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js"></script>

如果你不想包含 Lo-Dash,你可以很容易地自己实现 _.after:

function callAfter(n, func) {
  var i = 0;
  return function () {
    if (i < n) { i++; }
    else { return func(); }
  };
}

关于javascript - 在多个 setInterval 函数完成时执行代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27585511/

相关文章:

javascript - 添加和减去额外的类

javascript - 如何将 prettier-js.el 集成到 spacemacs 中

javascript - Prototype.js 和数组中的类继承

html - 将鼠标悬停在文本上适用于一张图片,但不适用于另一张图片。提供了我的 CodePen

html - Chrome 中的 Arial 窄字体问题

javascript - 适用于移动设备的 PhoneGap 和适用于桌面+移动设备的 Appcelerator?

javascript - 在 HTML 中显示 Vue 计算对象数组

java - Spark java嵌入式Jetty内部并发

multithreading - 为什么在仿真的 ubuntu 中使用 theora 编码时 2 个线程比 1 个慢?

java - 为什么选择私有(private)锁