这篇翻译不完整。请帮忙从英语翻译这篇文章

在指定的延迟时间之后调用一个函数或执行一个代码片段.

语法

var timeoutID = window.setTimeout(func, delay, [param1, param2, ...]);
var timeoutID = window.setTimeout(code, delay);

说明:

  • timeoutID 是该延时操作的数字ID, 此ID随后可以用来作为window.clearTimeout方法的参数.
  • func 是你想要在delay毫秒之后执行的函数.
  • code 在第二种语法,是指你想要在delay毫秒之后执行的代码字符串 (使用该语法是不推荐的, 不推荐的原因和eval()一样)
  • delay 是延迟的毫秒数 (一秒等于1000毫秒),函数的调用会在该延迟之后发生。如果省略该参数,delay取默认值0。实际的延迟时间可能会比 delay 值长,原因请查看下面的备注。

需要注意的是,IE9 及更早的 IE 浏览器不支持第一种语法中向延迟函数传递额外参数的功能。如果你想要在IE中达到同样的功能,你必须使用一种兼容代码 (查看callback arguments 一段).

备注: 在Gecko 13之前 (Firefox 13.0 / Thunderbird 13.0 / SeaMonkey 2.10), Gecko会给延迟函数传递一个额外的参数,该参数表明了此次延迟操作实际延迟的毫秒数.现在,这个非标准的参数已经不存在了.

例子

下文的例子在网页中设置了两个简单的按钮,以触发 setTimeout 和 clearTimeout 方法:按下第一个按钮会在 2s 后显示一个警告对话框,并将此次 setTimeout 的延时 ID 保存起来。按下第二个按钮可以取消这次延时调用行为。

HTML 内容

<p>Live Example</p>
<button onclick="delayedAlert();">Show an alert box after two seconds</button>
<p></p>
<button onclick="clearAlert();">Cancel alert before it happens</button>
 
 
 
 

JavaScript 内容

var timeoutID;

function delayedAlert() {
  timeoutID = window.setTimeout(slowAlert, 2000);
}

function slowAlert() {
  alert("That was really slow!");
}

function clearAlert() {
  window.clearTimeout(timeoutID);
}
 
 
 
 
 
 
 
 
 
 
 
 
 

也可参考 clearTimeout() 示例.

回调参数

如果你需要向你的回调函数内传递一个参数, 而且还需要兼容IE9及以前的版本, 由于IE不支持传递额外的参数 (setTimeout() 或者 setInterval()都不可以) ,但你可以引入下面的兼容代码.该代码能让IE也支持符合HTML5标准的定时器函数.

/*\
|*|
|*|  IE-specific polyfill which enables the passage of arbitrary arguments to the
|*|  callback functions of javascript timers (HTML5 standard syntax).
|*|
|*|  https://developer.mozilla.org/en-US/docs/DOM/window.setInterval
|*|
|*|  Syntax:
|*|  var timeoutID = window.setTimeout(func, delay, [param1, param2, ...]);
|*|  var timeoutID = window.setTimeout(code, delay);
|*|  var intervalID = window.setInterval(func, delay[, param1, param2, ...]);
|*|  var intervalID = window.setInterval(code, delay);
|*|
\*/

if (document.all && !window.setTimeout.isPolyfill) {
  var __nativeST__ = window.setTimeout;
  window.setTimeout = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) {
    var aArgs = Array.prototype.slice.call(arguments, 2);
    return __nativeST__(vCallback instanceof Function ? function () {
      vCallback.apply(null, aArgs);
    } : vCallback, nDelay);
  };
  window.setTimeout.isPolyfill = true;
}

if (document.all && !window.setInterval.isPolyfill) {
  var __nativeSI__ = window.setInterval;
  window.setInterval = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) {
    var aArgs = Array.prototype.slice.call(arguments, 2);
    return __nativeSI__(vCallback instanceof Function ? function () {
      vCallback.apply(null, aArgs);
    } : vCallback, nDelay);
  };
  window.setInterval.isPolyfill = true;
}

IE Only Fix

如果你需要单独的针对IE9及之前浏览器的 hack 写法,你可以使用 JavaScript 条件注释:

/*@cc_on
  // conditional IE < 9 only fix
  @if (@_jscript_version <= 9)
  (function(f){
     window.setTimeout =f(window.setTimeout);
     window.setInterval =f(window.setInterval);
  })(function(f){return function(c,t){var a=[].slice.call(arguments,2);return f(function(){c.apply(this,a)},t)}});
  @end
@*/
 
 
 
 
 
 
 
 
 

或者使用更加清晰的 IE HTML 条件注释:

<!--[if lte IE 9]><script>
(function(f){
    window.setTimeout =f(window.setTimeout);
    window.setInterval =f(window.setInterval);
})(function(f){return function(c,t){
    var a=[].slice.call(arguments,2);
    return f(function(){c.apply(this,a)},t)}
});
</script><![endif]-->
 
 
 
 
 
 
 
 

另一种方法是使用匿名函数包裹你的回调函数,这种方式要消耗更多资源:

var intervalID = setTimeout(function() { myFunc("one", "two", "three"); }, 1000);
 

此外,也可使用 function's bind

setTimeout(function(arg1){}.bind(undefined, 10), 1000);

关于"this"的问题

当你向 setTimeout() (或者其他函数也行)传递一个函数时,该函数中的this会指向一个错误的值.这个问题在 JavaScript reference 中进行了详细解释.

解释

由setTimeout()调用的代码运行在与所在函数完全分离的执行环境上. 这会导致,这些代码中包含的 this 关键字会指向 window (或全局)对象,这和所期望的this的值是不一样的.查看下面的例子:

myArray = ["zero", "one", "two"];
myArray.myMethod = function (sProperty) {
    alert(arguments.length > 0 ? this[sProperty] : this);
};

myArray.myMethod(); // prints "zero,one,two"
myArray.myMethod(1); // prints "one"
setTimeout(myArray.myMethod, 1000); // prints "[object Window]" after 1 second
setTimeout(myArray.myMethod, 1500, "1"); // prints "undefined" after 1,5 seconds
// let's try to pass the 'this' object
setTimeout.call(myArray, myArray.myMethod, 2000); // error: "NS_ERROR_XPC_BAD_OP_ON_WN_PROTO: Illegal operation on WrappedNative prototype object"
setTimeout.call(myArray, myArray.myMethod, 2500, 2); // same error

正如你所看到的一样,我们没有任何方法将this对象传递给回调函数.

解决方案

一个可用的解决 "this" 问题的方法是使用两个非原生的setTimeout()setInterval() 全局函数代替原生的.该非原生的函数通过使用Function.prototype.call 方法激活了正确的作用域.下面的代码显示了应该如何替换:

// Enable the passage of the 'this' object through the JavaScript timers
 
var __nativeST__ = window.setTimeout, __nativeSI__ = window.setInterval;
 
window.setTimeout = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) {
  var oThis = this, aArgs = Array.prototype.slice.call(arguments, 2);
  return __nativeST__(vCallback instanceof Function ? function () {
    vCallback.apply(oThis, aArgs);
  } : vCallback, nDelay);
};
 
window.setInterval = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) {
  var oThis = this, aArgs = Array.prototype.slice.call(arguments, 2);
  return __nativeSI__(vCallback instanceof Function ? function () {
    vCallback.apply(oThis, aArgs);
  } : vCallback, nDelay);
};
备注: 这两个替换也让 IE支持了符合 HTML5 标准的定时器函数。所以也能作为一个 polyfills。查看 Callback arguments 一段.

新特性检测:

myArray = ["zero", "one", "two"];
myArray.myMethod = function (sProperty) {
    alert(arguments.length > 0 ? this[sProperty] : this);
};

setTimeout(alert, 1500, "Hello world!"); // the standard use of setTimeout and setInterval is preserved, but...
setTimeout.call(myArray, myArray.myMethod, 2000); // prints "zero,one,two" after 2 seconds
setTimeout.call(myArray, myArray.myMethod, 2500, 2); // prints "two" after 2,5 seconds

针对这个问题并没有原生的解决方案。

注:JavaScript 1.8.5 引入了 Function.prototype.bind() 方法,该方法允许显式地指定函数调用时 this 所指向的值 。该方法可以帮助你解决 this 指向不确定的问题。

使用bind的例子:

myArray = ["zero", "one", "two"];
myBoundMethod = (function (sProperty) {
    console.log(arguments.length > 0 ? this[sProperty] : this);
}).bind(myArray);

myBoundMethod(); // prints "zero,one,two" because 'this' is bound to myArray in the function
myBoundMethod(1); // prints "one"
setTimeout(myBoundMethod, 1000); // still prints "zero,one,two" after 1 second because of the binding
setTimeout(myBoundMethod, 1500, "1"); // prints "one" after 1.5 seconds

备注

你可以使用 window.clearTimeout()来取消延迟操作。如果你希望你的代码被重复的调用 (比如每 N 毫秒一次),考虑使用 window.setInterval()

记住这一点:只有当调用setTimeout()的线程停止后,函数或代码段才能继续执行。

传递字符串字面量

setTimeout()传递一个字符串而不是函数会遭受到与使用eval一样的风险.

// 正确
window.setTimeout(function() {
    alert("Hello World!");
}, 500);

// 不正确
window.setTimeout("alert(\"Hello World!\");", 500);

字符串会在全局作用域内被解释执行,所以当setTimeout()函数执行完毕后,字符串中的变量不可用.

最小延迟和超时嵌套

Historically browsers implement setTimeout() "clamping": successive setTimeout() calls with delay smaller than the "minimum delay" limit are forced to the use at least the minimum delay. The minimum delay, DOM_MIN_TIMEOUT_VALUE, is 4 ms (stored in a preference in Firefox: dom.min_timeout_value), with a DOM_CLAMP_TIMEOUT_NESTING_LEVEL of 5ms.

In fact, 4ms is specified by the HTML5 spec and is consistent across browsers released in 2010 and onward. Prior to (Firefox 5.0 / Thunderbird 5.0 / SeaMonkey 2.2), the minimum timeout value for nested timeouts was 10 ms.

In addition to "clamping", the timeout can also fire later when the page (or the OS/browser itself) is busy with other tasks.

To implement a 0 ms timeout in a modern browser you can use window.postMessage() as described here.

Inactive tabs

In (Firefox 5.0 / Thunderbird 5.0 / SeaMonkey 2.2) and Chrome 11, timeouts are clamped to firing no more often than once per second (1000ms) in inactive tabs; see bug 633421 for more information about this in Mozilla or crbug.com/66078 for details about this in Chrome.

浏览器兼容性

Feature Chrome Firefox (Gecko) Internet Explorer Opera Safari
Basic support 1.0 1.0 (1.7 or earlier) 4.0 4.0 1.0
Supports parameters for callback*1 (Yes) (Yes) 10.0 (Yes) ?
Feature Android Chrome for Android Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile
Basic support 1.0 1.0 1.0 (1) 6.0 6.0 1.0
Supports parameters for callback*1 ? ? ? ? ? ?

*1 Whether it supports the optional parameters when in its first form or not.

规范

Part of DOM level 0, as specified in HTML5.

参考

文档标签和贡献者

 此页面的贡献者: SnowOnion, Chimen, hbkdsm, paddingme, teoli, khalid32, Meteormatt, ziyunfei
 最后编辑者: SnowOnion,