JS计数器函数执行过程解读(3)
3、异步测试
另外一种中央计时器控件能派上用场的情况是在你打算做异步测试的时候。这里的问题是当我们需要对没有立即完成的计算执行测试时(如计时器内的一些行为或XMLHttpRequest)。我们需要将测试包分解,这样就会完全异步工作。
例如,在一个正常的测试包中,我们可以很容易的运行这些测试。但是,一旦在我们的测试中引入这种需求,我们需要分解它们并单独处理。我们可以用下面的代码达到我们期望的效果。
简单的异步测试包:
(function(){
var queue = [], timer;
this.test = function(fn){
queue.push( fn );
resume();
};
this.pause = function(){
clearInterval( timer );
timer = 0;
};
this.resume = function(){
if ( !timer )
return;
timer = setInterval(function(){
if ( queue.length )
queue.shift()();
else
pause();
}, 1);
};
})();
test(function(){
pause();
setTimeout(function(){
assert( true, "First test completed" );
resume();
}, 100);
});
test(function(){
pause();
setTimeout(function(){
assert( true, "Second test completed" );
resume();
}, 200);
});
最重要的一个方面是,传递给test()的每一个函数至多包含一个异步测试。其异步性是通过使用pause()和resume()函数来定义的,这些函数在异步事件前后调用。实际上,上面的代码只不过是保持异步行为的一种手段--其包含的函数以特定的顺序执行(它不完全用于本测试包,但在这非常有用)。
让我们看看使这种行为成为可能的代码。函数的大部分功能包含在resume()函数中,它的行为与我们前面例子中的start()方法相似,但它主要用来处理队列数据,其主要目的是取出一个函数并执行它。如果有一个在等待,它将完全停止运行。最重要的方面是,既然队列处理代码完全是异步的,他就能保证在我们调用pause()函数之后尝试执行。
这一段简短的代码使我们的测试以完全异步的方式执行,但仍维持着test()函数执行的顺序(如果结果具有毁坏性且影响其它测试,这就非常关键)。谢天谢地,我们可以看到,使用最有效的计时器,给一个存在的测试包增加可靠的异步测试并不需要所有的开销。