一句代码让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);
2013年6月7日 | 归档于 技术, 程序
  1. 2013年6月8日 09:18 | #1

    好蛋疼的实验~

发表评论

XHTML: 您可以使用这些标签: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>
:wink: :-| :-x :twisted: :) 8-O :( :roll: :-P :oops: :-o :mrgreen: :lol: :idea: :-D :evil: :cry: 8) :arrow: :-? :?: :!: