JavaScript定时器管理中心

JavaScript定时器管理中心

  上一篇文章说到了如果一个页面出现太多定时器,推荐使用定时器管理中心进行管理并且回收,这也是jQuery作者所推荐的。有兴趣的可以看看Stackoverflow上面一个问题:使用定时器实现动画

  其实这个管理中心的底层就是用setTimeout函数做的,只不过把所有的定时器都放在一个timerManager对象的itemList属性里面,然后不断轮询,查看其下一个最接近当前时间的定时器,然后进行setTimeout()。

这个管理中心的如以下代码(我已经写好了注释,方便理解,如果发现错误,欢迎指出)

var timerManager = {
  itemList: [], //用来装载每个定时器的信息[{定时器1},{定时器2},……]
  idCnt: 0,   //作为每个定时器的id,每加一个就自加1
  timer: null,    //L:45  装载当前执行的setTimeout(function(),now)
  timeout: 0 // 毫秒单位 装载上次定时器的所设定的运行时间
};
//Loop为-1的时候无限执行
//添加定时器
timerManager.addTimer = function (loop, interval, callback) {
  if (interval <= 0) {
    callback();
    return;
  }
  var nowTime = new Date().getTime();
  var id = this.idCnt;
  this.itemList.push({
    id: id, //定时器ID
    loop: loop, //循环次数
    fireCnt: 0,  //计算已经运行的次数
    timeout: nowTime + interval,   //下次运行的时间
    interval: interval,   //该定时器所定的o延迟执行时间
    callback: callback  //装载该定时器所执行的回调时间
  });
  this.idCnt++;   //为下次的定时器准备,定时器id自增1
  this.checkTimer(nowTime);    //轮询
  return id;
};
//轮询函数
timerManager.checkTimer = function (nowTime) {
  this.removeFinished();
  if (this.itemList.length <= 0 && this.timer != null) {    //没有定时器要执行
    console.log("checkTimer itemList is empty, clear timer!");
    this.clearTimer();   
    return;
  }
  if (!nowTime) {   //获取现在的时间
    nowTime = new Date().getTime();
  }
  var newTimeout = 0;  //装载最接近执行时间的那个定时器执行时间
  for (var i = 0; i < this.itemList.length; i++) {
    var item = this.itemList[i];    //获取当前位置的定时器所定义的属性
    if (newTimeout == 0 || newTimeout > item.timeout) {
      newTimeout = item.timeout;   
    }
  }
  //如果没有执行的定时器  
  //或者当前最接近的时间小于上次执行的那个定时器的时间
  //或者已经“够钟”执行
  //3者满足其一即可
  if (this.timer == null || newTimeout < this.timeout || this.timeout < nowTime) {
    this.clearTimer();
    // Math.max(newTimeout - nowTime, 0)  
    //主要是以防出现负数的情况,所以从2个参数里面选择最大的那个,所以出现的最小的情况为0;
    this.timer = setTimeout(this.onTimer, Math.max(newTimeout - nowTime, 0));
    this.timeout = newTimeout;
  }
};
//执行的回调函数
timerManager.onTimer = function () {
  var nowTime = new Date().getTime();
  for (var i = 0; i < timerManager.itemList.length; i++) {
    var item = timerManager.itemList[i];
    //‘够钟’执行回调函数
    if (nowTime >= item.timeout) {
      item.callback();
      item.fireCnt++;
      item.timeout = nowTime + item.interval;
    }
  }
  timerManager.clearTimer();
  timerManager.checkTimer(nowTime);   //继续轮询
};
timerManager.clearTimer = function () {  //清除执行的定时器
  if (this.timer != null) {
    clearTimeout(this.timer);
    this.timer = null;
  }
};
timerManager.removeFinished = function () {   //删除已经完成的定时器
  for (var i = this.itemList.length - 1; i >= 0; i--) {   //从后往前遍历
    var item = this.itemList[i];
    if (item.loop >= 0 && item.fireCnt >= item.loop) {   //如果循环次数loop大于等于0,并且已经执行次数已经超过或者等于一开始所赋值的次数
      this.itemList.splice(i, 1);   //删掉该定时器
    }
  }
};
timerManager.stop = function () {  //删除所有定时器
  this.clearTimer();
  this.itemList = null;
  this.timeout = 0;
};
timerManager.stopOneTimer = function (timerId) {   //删除单个定时器
  for (var i = 0; i < this.itemList.length; i++) {
    if (this.itemList[i].id == timerId) {
      this.itemList.splice(i, 1);
    }
  }
};

代码就这些,如果阅读代码的时候发现有问题欢迎指出来

参考文章:你真的了解setTimeout和setInterval吗?

你可能感兴趣的:(javascript)