打印

BX9011: 各浏览器对 setTimeout 方法传入时间参数的某些极端值的处理存在差异

作者:陆远

标准参考

无。

问题描述

setTimeout 方法的时间参数若为极端值(如负数、0、或者极大的正数),则各浏览器的处理会出现较大差异,某些浏览器会立即执行。

造成的影响

此问题会造成不同浏览器中执行代码的时刻出现差异,可能造成后面的脚本出错。

受影响的浏览器

所有浏览器  

问题分析

setTimeout 方法通常的调用语法为:setTimeout(code, millisec)。其用于在 millisec 参数指定的毫秒数之后调用 code 参数中的代码或者是函数表达式,setTimeout 方法中的代码仅执行一次。

关于 setTimeout 方法的更多信息,

各种规范草案及官方文档中均为提及 setTimeout 方法中设定毫秒数的参数的取值范围。下面将针对一些极端值进行测试。

<!DOCTYPE html>
<html>
<head>
</head>
<body style="font:24px Consolas;">
<div>setTimeout: N/A</div>
<script>
  setTimeout(function () {
    document.getElementsByTagName("div")[0].innerHTML = 'setTimeout: Trigger';
  }, -10);
</script>
</body>
</html>

上面代码为 setTimeout 方法设定了一个值为 -10 的时间参数。

各浏览器中运行效果如下:

IE6 IE7 IE8 Firefox Chrome Safari Opera
setTimeout: N/A setTimeout: Trigger

可见,对于值为 -10 的时间参数,在 Firefox Chrome Safari Opera 中立即执行2了代码。而在 IE 中则没有执行,可以看作各浏览器进入了代码延时执行环节。

注 1: 此处以及之后的立即执行是指与 setTimeout (func,0) 执行情况相同,即在完成当前执行流后的延时执行情况。


<!DOCTYPE html>
<html>
<head>
</head>
<body style="font:24px Consolas;">
<div>setTimeout: N/A</div>
<script>
  setTimeout(function () {
    document.getElementsByTagName("div")[0].innerHTML = 'setTimeout: Trigger';
  }, -2147483649);
</script>
</body>
</html>

上面代码为 setTimeout 方法设定了一个值为 -2147483649 的时间参数。

各浏览器中运行效果如下:

IE6 IE7 IE8 Firefox Chrome Safari Opera
setTimeout: N/A setTimeout: Trigger

可见,对于值为 -2147483649 的时间参数, Opera 立即执行了代码。而在 其他浏览器中则没有执行,可以看作各浏览器进入了代码延时执行环节。


<!DOCTYPE html>
<html>
<head>
</head>
<body style="font:24px Consolas;">
<div>setTimeout: N/A</div>
<script>
  setTimeout(function () {
    document.getElementsByTagName("div")[0].innerHTML = 'setTimeout: Trigger';
  }, Infinity);
</script>
</body>
</html>

上面代码为 setTimeout 方法设定了一个值为 Infinity 的时间参数。

各浏览器中运行效果如下:

IE6 IE7 IE8 Firefox Chrome Safari Opera
setTimeout: N/A setTimeout: Trigger

可见,对于值为 Infinity 的时间参数,Opera 立即执行了代码。而在其他浏览器中则没有执行,这有两种可能存在,一为此参数无效被忽略,二为浏览器已经进入大数延时执行状态;但是我们无法确切知道是各浏览器中实际执行的是哪种情况,因为等待他们执行需要的时间太长了。


<!DOCTYPE html>
<html>
<head>
</head>
<body style="font:24px Consolas;">
<div>setTimeout: N/A</div>
<script>
  setTimeout(function () {
    document.getElementsByTagName("div")[0].innerHTML = 'setTimeout: Trigger';
  }, 2147483647);
</script>
</body>
</html>

上面代码为 setTimeout 方法设定了一个值为 2147483647 的时间参数。

各浏览器中运行效果如下:

IE6 IE7 IE8 Firefox Chrome Safari Opera
setTimeout: N/A

可见,所有浏览器对于值为 2147483647 的时间参数,运行后代码均没有很快被执行,这说明各浏览器仅进入了延时执行环节。


<!DOCTYPE html>
<html>
<head>
</head>
<body style="font:24px Consolas;">
<div>setTimeout: N/A</div>
<script>
  setTimeout(function () {
    document.getElementsByTagName("div")[0].innerHTML = 'setTimeout: Trigger';
  }, 2147483648);
</script>
</body>
</html>

上面代码为 setTimeout 方法设定了一个值为 2147483648 的时间参数。

各浏览器中运行效果如下:

IE6 IE7 IE8 Opera Firefox Chrome Safari
setTimeout: N/A setTimeout: Trigger

可见,对于值为 Infinity 的时间参数,在 Firefox Chrome Safari 中立即执行了代码。而在 IE Opera 中则没有执行,可以看作各浏览器进入了代码延时执行环节。


统计各浏览器对于 setTimeout 方法传入的时间参数的极端值的处理并无实际意义,这其中涉及到浏览器内核的实现,以及整型溢出等问题。但通过上面的测试样例已经可以看出各浏览器对于极大、负值的事件参数的处理有很大的差异。

解决方案

明确使用 setTimeout 方法的意义,若不希望代码被执行则应通过其他方法达到类似的效果,而不能依赖于为 setTimeout 方法设定极端的时间参数;负数的时间参数是无意义的,应避免使用,若希望代码在当前执行流完成后立即执行,则应设定 0 作为参数。

参见

知识库

相关问题

测试环境

操作系统版本: Windows 7 Ultimate build 7600
浏览器版本: IE6
IE7
IE8
Firefox 3.6.9
Chrome 7.0.517.5 dev
Safari 5.0.2
Opera 10.62
测试页面: settimeout.html
本文更新时间: 2010-09-14

关键字

setTimeout setInterval timer 定时 时间