我们已经看到,异步函数非常适合用于I/O操作,但有些时候,我们仅仅是因为需要异步而想要异步性。换句话说,我们想让一个函数在将来某个时刻再运行——这样的函数可能是为了作动画或模拟。基于时间的事件涉及两个著名的函数,即setTimeout与setInterval。 遗憾的是,这两个著名的计时器函数都有自己的一些缺陷。正如我们在1.1.2节中看到的,其中有个缺陷是无法弥补的:当同一个JavaScript进程正运行着代码时,任何JavaScript计时函数都无法使其他代码运行起来。但是,即便容忍了这一局限性,setTimeout及setInterval的不确定性也会令人犯怵。下面是一个示例。 EventModel/fireCount.js var fireCount = 0; var start = new Date; var timer = setInterval(function() { if (new Date-start > 1000) { clearInterval(timer); console.log(fireCount); return; } fireCount++; }, 0); 如果使用setInterval调度事件且延迟设定为0毫秒,则会尽可能频繁地运行此事件,对吗?那么,在运行于高速英特尔i7处理器之上的现代浏览器中,此事件的触发频率到底如何呢? 大约为200次/秒。这是Chrome、Safari和Firefox等浏览器的平均值。在Node环境下,此事件的触发频率大约能达到1000次/秒。(若使用setTimeout来调度事件,重复这些实验也会得到类似的结果。)作为对比,如果将setInterval替换成简单的while循环,则在Chrome中此事件的触发频率将达到400万次/秒,而在Node中会达到500万次/秒! 这是怎么回事?最后我们发现,setTimeout和setInterval就是想设计成慢吞吞的!事实上,HTML规范(这是所有主要浏览器都遵守的规范)推行的延时/时隔的最小值就是4毫秒! 那么,如果需要更细粒度的计时,该怎么办呢?有些运行时环境提供了备选方案。 在Node中,process.nextTick允许将事件调度成尽可能快地触发。对于笔者的系统,process.nextTick事件的触发频率可以超过10万次/秒。 一些现代浏览器(含IE9+)带有一个requestAnimationFrame函数。此函数有两个目标:一方面,它允许以60+帧/秒的速度运行JavaScript动画;另一方面,它又避免后台选项卡运行这些动画,从而节约CPU周期。在最新版的Chrome浏览器中,甚至能实现亚毫秒级的精度。 尽管这些计时函数是异步JavaScript混饭吃的家伙什儿,但永远不要忘记,setTimeout和setInterval就是些不精确的计时工具。在Node中,如果只是想产生一个短时延迟,请使用process.nextTick。在浏览器端,请尝试使用垫片技术(shim) :在支持requestAnimationFrame的浏览器中,推荐使用requestAnimationFrame;在不支持requestAnimationFrame的浏览器中,则退而使用setTimeout。 到这里,关于JavaScript基本异步函数的简要概览就结束了。但怎样才能知道一个函数到底何时异步呢?下一节中,我们在亲自编写异步函数的同时再思考这个问题。
JavaScript异步编程——1.2.2 异步的计时函数
书名: JavaScript异步编程
作者: [英] Trevor Burnham
出版社: 人民邮电出版社
原作名: Async JavaScript: Build More Responsive Apps with Less Code
副标题: 设计快速响应的网络应用
译者: 许青松
出版年: 2013-6
页数: 118
定价: 32.00元
装帧: 平装
丛书: 图灵程序设计丛书
ISBN: 9787115316578