一句代码让JavaScript阻塞N秒
JavaScript有异步机制,没有必要故意阻塞线程N秒。
而且由于JavaScript的单线程执行特性,使得即使成功将线程停下来,由于没有第二个线程干活,阻塞也没有意义。另外,脚本被阻塞时,页面是停止响应的。
话说回来,如何去实现这个阻塞N秒呢?一要比较精准,二要对所有浏览器都无区别适用。
很自然想到循环执行一个代码段,执行X次,刚好消耗N秒,问题是浏览器的JS引擎性能不一致,这个次数不是恒值,而且还跟当前CPU的空闲状态相关
首先来看死循环:
while(2>1){};
嗯,脚本被永远阻塞了。
不妨假设N秒为5秒。如果刚好5秒计时到了就跳出循环的话:
var s = +new Date(); while(2>1) { if (+new Date() > s + 5000) { break; } }
有了一个能刚好阻塞5秒的平台无关例子了,下面看看怎么将它缩短到1行代码
很显然可以将跳出条件作为while的循环条件
var s = +new Date(); while(s + 5000 > +new Date()) {}
嗯,缩短到了两行了。
for循环可以将变量放在初始条件声明,于是
for(var s = +new Date(); s + 5000 > +new Date();){}
一行达成!
将脚本阻塞5秒,循环体内又什么都不干,相当蛋疼。
将一个任务队列,比如函数数组,放在循环体内pop出来执行,大概上相当于:给你们最多5秒时间,干不完就算了!
只是最后一个执行函数如果占用超过5秒,总体时间也是不能保证的
最后是一些引擎的性能:
for(var s = +new Date(), i = 0; s + 5000 > +new Date(); i++){} alert(i);
余的电脑,chrome27大概能执行290万次,firefox21大概能执行154万次,IE8大概能执行216万次
一次循环的运算大体上是:创建一个新的Date对象,将Date对象转换为数字,一次加法运算,一次比较运算,一次循环判断,一次自加运算
比较意外IE8居然比firefox性能好,firefox上,每次循环平均耗时0.0032毫秒。
单次循环的耗时还能下降一点,因为每次s+5000是不必要的
for(var s = +new Date() + 5000, i = 0; s > +new Date(); i++){} alert(i);
循环次数大概能提高2~3万次。
逆过来循环i次,大体上在每个浏览器上都能得到5秒的延时
for(var s = +new Date()+5000, i = 0; s > +new Date(); i++){} var start = +new Date(); for (;i--;) {s > +new Date();} alert(+new Date() - start);
好蛋疼的实验~