这是一个简单实用的工具,用于定期执行一个指定的函数。从本质上来说,它是封装原生 Window 对象的 setInterval/clearInterval 机制。

PeriodicalExecuter 具有一项值得注意的非常有用的特性:它会阻止回调函数的多次并发执行, 并顺延执行的时间间隔(它维护一个内部的运行标志,用于屏蔽回调函数运行时的产生的异常)。如果需要定时与用户进行交互 (如使用一个 promptconfirm),这非常有用,它将会避免在等待响应时产生多个信息框。

当然,当前一个非常好的观点是:应尽量使用一个实际的对象,而不是维护一个全局的定时器句柄。这也算是 PeriodicalExecuter 的一项优势吧。

创建 PeriodicalExecuter 对象

PeriodicalExecuter 的构造函数有两个参数:回调函数和时间间隔(以为单位)。 该对象启动后,会无限制的触发执行回调函数,直到页面卸载为止(浏览器通常会在一个适当的时机清除所有的定时器和延时器)。 当然,你也可以调用 stop 方法手动停止。

new PeriodicalExecuter(pollChatRoom, 3); 
new PeriodicalExecuter(function(pe) { 
	if (!confirm('Want me to annoy you again later?')) 
		pe.stop(); 
}, 5); 
// 注意,即使用户长时间不响应,这里也不会弹出一大堆询问信息

译注:其实对于上面的样例,简单的使用原生的 setInterval 也不会弹出一大堆的信息框(包括 IE 和 FireFox),甚至于在浏览器中要弹出一大堆信息框还是一件困难的事。所以对于该文第二段的解释,我觉得有些勉强,或许是我理解有误?
使用 setInterval 实现上述例子:

var interval = setInterval(function(){
	if (!confirm('Want me to annoy you again later?')) 
		clearInterval(interval);
}, 5000)

方法

stop

stop()

停止 PeriodicalExecuter 的执行,回调函数不会再次被触发。

PeriodicalExecuter 被创建后,它会构成一个无限循环,按照给定的时间间隔触发回调,直到页面被卸载为止。 这个方法让你能够随时中止循环。

PeriodicalExecuter 被中止后,虽然在技术上可以通过 registerCallback 方法再次启用, 但这会让人感到混淆不清,究竟是应该把 registerCallback 当作一个内部方法(因此不能作为一项功能使用), 还是当作外部方法。既然存在疑问,那么当需要启动一个定时器时,还是实例化一个新的 PeriodicalExecuter 吧。

译注:其实我倒觉得有一个重新启动的方法,这个主意不错,如果你有和我一样的想法, 那么可以按照下面的方法扩展代码:

PeriodicalExecuter.prototype.resume = function(){
	if(!this.timer)
		this.registerCallback();
}; 

扩展完成后,可以这样使用:

var pe = new PeriodicalExecuter(function(){
	alert('这是一个测试样例!');
}, 5);

// 如果要停止
pe.stop();
// 停止后再重新启动
pe.resume();

样例

var gCallCount = 0; 
new PeriodicalExecuter(function(pe) { 
	if (++gCallCount > 3) 
		pe.stop(); 
	else 
		alert(gCallCount); 
}, 1); 
// 只会弹出 1, 2, 3,然后停止。