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);
}
}
};
代码就这些,如果阅读代码的时候发现有问题欢迎指出来