W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
WindowOrWorkerGlobalScope mixin 的 setTimeout() 方法 (以及 window.setTimeout 的后繼)用于設(shè)置一個定時器,該定時器在定時器到期后執(zhí)行一個函數(shù)或指定的一段代碼。
var timeoutID = scope .setTimeout(function [,delay,param1,param2,...]);
var timeoutID = scope .setTimeout(function [,delay ]);
var timeoutID = scope .setTimeout(code [,delay ]);
eval()
安全風(fēng)險的相同原因而使用此語法。注意:在 Internet Explorer 9 及更低版本中,將第一種語法的附加參數(shù)傳遞給函數(shù)不起作用。如果您想在該瀏覽器上啟用此功能,則必須使用填充(polyfill),請參考本文的 Polyfill 部分。
setTimeout() 方法返回的 timeoutID 是一個正整數(shù)值,用于標(biāo)識由該 setTimeout() 調(diào)用創(chuàng)建的定時器;這個值可以傳遞 clearTimeout() 以取消超時。
了解 setTimeout() 和 setInterval() 共享相同的 ID 池可能會有所幫助,并且 clearTimeout() 和 clearInterval() 在技術(shù)上可以互換使用。但是,為了清晰起見,您應(yīng)該盡量始終與它們匹配以避免在維護(hù)代碼時出現(xiàn)混淆。
保證在同一對象(window 或 worker)上對 setTimeout () 或 setInterval () 的后續(xù)調(diào)用將永遠(yuǎn)不會重用超時 ID。但是,不同的對象使用單獨的 ID 池。
以下示例在網(wǎng)頁中設(shè)置兩個簡單按鈕并將它們掛接到該例程 setTimeout() 和 clearTimeout()例程。按下第一個按鈕將設(shè)置一個超時,在兩秒鐘后調(diào)用一個警報對話框,并存儲要使用的 clearTimeout() 超時 ID。您可以選擇通過按第二個按鈕來取消該超時。
<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>
var timeoutID;
function delayedAlert() {
timeoutID = window.setTimeout(slowAlert, 2000);
}
function slowAlert() {
alert('That was really slow!');
}
function clearAlert() {
window.clearTimeout(timeoutID);
}
如果您需要將一個或多個參數(shù)傳遞給您的回調(diào)函數(shù),但需要它在不支持使用 setTimeout() 或者 setInterval() (例如 Internet Explorer 9 及以下版本)發(fā)送附加參數(shù)的瀏覽器中工作),則可以包括此填充代碼,其中啟用 HTML5 標(biāo)準(zhǔn)參數(shù)傳遞功能,只需將此代碼添加到腳本的頂部即可:
/*\
|*|
|*| 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);
|*|
\*/
(function() {
setTimeout(function(arg1) {
if (arg1 === 'test') {
// feature test is passed, no need for polyfill
return;
}
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);
};
}, 0, 'test');
var interval = setInterval(function(arg1) {
clearInterval(interval);
if (arg1 === 'test') {
// feature test is passed, no need for polyfill
return;
}
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);
};
}, 0, 'test');
}())
如果您希望對其他移動瀏覽器或桌面瀏覽器(包括 IE 9 及以下版本)進(jìn)行完全不引人注意的攻擊,則可以使用 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 instanceof Function?c.apply(this,a):eval(c)},t)}});
@end
@*/
或者根據(jù) 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 instanceof Function?c.apply(this,a):eval(c)},t)}
});
</script><![endif]-->
另一種可能是使用 anonymous 函數(shù)來調(diào)用你的回調(diào)函數(shù),但是這個解決方案有點消耗,例如:
var intervalID = setTimeout(function() { myFunc('one', 'two', 'three'); }, 1000);
上面的例子也可以在 arrow 函數(shù)的幫助下編寫:
var intervalID = setTimeout(() => { myFunc('one', 'two', 'three'); }, 1000);
另一種可能性是使用函數(shù)的 bind,例如:
setTimeout(function(arg1){}.bind(undefined, 10), 1000);
當(dāng)你傳遞一個方法給 setTimeout()(或任何其他函數(shù))時,它會被一個 this 值調(diào)用,這可能與你的期望不同的。
由 setTimeout() 執(zhí)行的代碼是從調(diào)用 setTimeout 的函數(shù)分開的執(zhí)行上下文中調(diào)用。通常 this 為被調(diào)用函數(shù)設(shè)置關(guān)鍵字的規(guī)則適用,如果您未在調(diào)用中設(shè)置 this 或使用 bind,在非嚴(yán)格模式它將默認(rèn)為 global(或 window)對象,或者在嚴(yán)格模式下未定義。它將與調(diào)用 setTimeout 的函數(shù)的 this 值不相同。
注意:即使在嚴(yán)格模式下,回調(diào)的默認(rèn) this 值 setTimeout 仍然是 window 對象,而不是 undefined。
看下面的例子:
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"
上面的工作是因為當(dāng) myMethod 被調(diào)用時,通過調(diào)用,this 被設(shè)置為 myArray,所以在該函數(shù)內(nèi),this[sProperty] 相當(dāng)于 myArray[sProperty]。但是,在以下內(nèi)容中:
setTimeout(myArray.myMethod, 1000); // prints "[object Window]" after 1 second
setTimeout(myArray.myMethod, 1500, '1'); // prints "undefined" after 1.5 seconds
該 myArray.myMethod 函數(shù)被傳遞給 setTimeout它,然后當(dāng)它被調(diào)用時,this 沒有被設(shè)置,所以它默認(rèn)為該 window 對象。也沒有選擇傳遞 thisArg 給setTimeout,因為在 Array 方法中有像 forEach,reduce 等等,并且如下所示,使用 call 設(shè)置 this 也不起作用。
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
解決該問題的常用方法是使用包裝函數(shù)設(shè)置 this 為所需值的:
setTimeout(function(){myArray.myMethod()}, 2000); // prints "zero,one,two" after 2 seconds
setTimeout(function(){myArray.myMethod('1')}, 2500); // prints "one" after 2.5 seconds
arrow 函數(shù)也是一種可能的選擇:
setTimeout(() => {myArray.myMethod()}, 2000); // prints "zero,one,two" after 2 seconds
setTimeout(() => {myArray.myMethod('1')}, 2500); // prints "one" after 2.5 seconds
解決這個 this 問題的另一種可能的方法是,將主機(jī) setTimeout() 和 setInterval() 全局函數(shù)替換為允許傳遞 this 對象并在使用 Function.prototype.call 的回調(diào)中設(shè)置它,例如:
// Enable setting 'this' in 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);
};
注意:這兩個替代品也將啟用 HTML5 標(biāo)準(zhǔn)的任意參數(shù)傳遞給 IE 中定時器的回調(diào)函數(shù)。所以他們也可以用作 polyfills。
新功能測試:
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
使用 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
使用 clearTimeout () 取消超時。要重復(fù)調(diào)用函數(shù)(例如,每N毫秒),請考慮使用setInterval()。
傳遞一個字符串而不是一個函數(shù)給 setTimeout(),承受與使用 eval 相同的危險。
// Recommended
window.setTimeout(function() {
alert('Hello World!');
}, 500);
// Not recommended
window.setTimeout("alert('Hello World!');", 500);
傳遞給 setTimeout 的字符串在全局上下文中被計算,因此在將字符串計算為代碼時,調(diào)用 setTimeout () 的上下文中的本地符號將不可用。
有多種原因可能會導(dǎo)致超時時間超出預(yù)期。本節(jié)介紹最常見的原因。
在目前使用的瀏覽器中,由于回調(diào)嵌套(嵌套層次至少達(dá)到一定深度),或者在一定數(shù)量的連續(xù)時間間隔后觸發(fā)連續(xù)調(diào)用時,setTimeout()/setInterval() 調(diào)用每4ms 至少被節(jié)流一次。例如:
function cb() { f(); setTimeout(cb, 0); }
setTimeout(cb, 0);
setInterval(f, 0);
在 Chrome 和 Firefox 中,第五個連續(xù)回調(diào)調(diào)用被夾緊;Safari 在第 6 次通話中夾緊;在 Edge 中它是第三個。Gecko 在版本56中開始這樣對待 setInterval()。
從歷史上看,一些瀏覽器實施這種限制行為有點不同(例如 Firefox) - setInterval() 從任何地方進(jìn)行調(diào)用,或者在 setTimeout() 嵌套級別至少達(dá)到特定深度時調(diào)用嵌套。
要在現(xiàn)代瀏覽器中實現(xiàn) 0 ms 超時,可以使用 window.postMessage(),如下所述。
注意:所述的最小延遲,DOM_MIN_TIMEOUT_VALUE 是 4 毫秒(存儲在Firefox 的首選項中: dom.min_timeout_value),DOM_CLAMP_TIMEOUT_NESTING_LEVEL 為 5。
注意:4 ms 由 HTML5 規(guī)范指定,并且在 2010 年及以后發(fā)布的瀏覽器中保持一致。在(Firefox 5.0/Thunderbird 5.0/SeaMonkey 2.2)之前,嵌套超時的最小超時值為10毫秒。
為了減少后臺選項卡中的負(fù)載(以及相關(guān)的電池使用),在非活動選項卡中,超時將被限制為每秒不超過一次(1000毫秒)觸發(fā)。
Firefox 從版本5開始實現(xiàn)這種行為(可以通過 dom.min_background_timeout_value 首選項調(diào)整 1000ms 常量)。Chrome 從版本11開始實施此行為(crbug.com/66078)。
Firefox 為 Android 使用15分鐘的超時值作為 Firefox 14 中錯誤 736602 的后臺選項卡,并且后臺選項卡也可以完全卸載。
如果 Web Audio API AudioContext 正在播放聲音,則 Firefox 50 不再限制后臺選項卡。Firefox 51 進(jìn)一步修正了這個問題,即使沒有聲音播放,如果標(biāo)簽中的 AudioContext 存在,后臺選項卡也不再被限制。這些解決了使用基于筆記的音樂的應(yīng)用程序在選項卡位于后臺時無法正確計時或同步音樂的許多問題。
自 Firefox 55 以來,跟蹤腳本(例如 Google Analytics,F(xiàn)irefox 通過其 TP 列表識別為跟蹤腳本的任何腳本 URL )都受到進(jìn)一步限制。在前臺運行時,節(jié)流最小延遲仍為 4ms。但是,在后臺選項卡中,限制最小延遲時間為10000毫秒或10秒,這將在文檔第一次加載后30秒生效。
控制這種行為的前提是:
除了“clamping”之外,當(dāng)頁面(或操作系統(tǒng)/瀏覽器本身)忙于其他任務(wù)時,超時還可以稍后觸發(fā)。需要注意的一個重要情況是,直到調(diào)用 setTimeout() 的線程已終止才能執(zhí)行該函數(shù)或代碼片段。例如:
function foo() {
console.log('foo has been called');
}
setTimeout(foo, 0);
console.log('After setTimeout');
將寫入控制臺:
After setTimeout
foo has been called
這是因為即使 setTimeout 被稱為延遲零,它被放置在一個隊列中,并計劃在下一個機(jī)會運行;不是馬上當(dāng)前執(zhí)行的代碼必須在執(zhí)行隊列上的函數(shù)之前完成,因此結(jié)果的執(zhí)行順序可能不如預(yù)期。
包括 Internet Explorer,Chrome,Safari 和 Firefox 在內(nèi)的瀏覽器將延遲存儲為內(nèi)部 32 位有符號整數(shù)。當(dāng)使用大于 2147483647 的延遲(大約24.8天)時,會導(dǎo)致整數(shù)溢出,導(dǎo)致立即執(zhí)行超時。
規(guī)范 | 狀態(tài) | 評論 |
---|---|---|
HTML Living Standard 在該規(guī)范中定義'WindowOrWorkerGlobalScope.setTimeout()'。 |
Living Standard |
方法轉(zhuǎn)移到最新規(guī)范中的WindowOrWorkerGlobalScope mixin。 |
HTML Living Standard 該規(guī)范
中'WindowTimers.setTimeout()'的定義。 |
Living Standard |
初始定義(DOM Level 0) |
我們正在將兼容性數(shù)據(jù)轉(zhuǎn)換為機(jī)器可讀的JSON格式。
特征 | Chrome |
Edge |
Firefox(Gecko) |
Internet Explorer |
Opera |
Safari |
---|---|---|---|---|---|---|
基本支持 | 支持:1.0 | 支持 | 支持:1.0(1.7或更早)、52[2] | 支持:4 | 支持:4 | 支持:1.0 |
支持回調(diào)參數(shù)[1] | 支持 | 支持 | 支持 | 支持:10.0 | 支持 | 支持 |
限制跟蹤超時腳本 | ? | ? | 支持:55 | ? | ? | ? |
特征 | Android | Chrome for Android | Edge | Firefox Mobile (Gecko) | IE Mobile | Opera Mobile | Safari Mobile |
---|---|---|---|---|---|---|---|
基本支持 | 支持:1.0 | 支持:1.0 | 支持 | 支持:1.0、52.0[2] | 支持:6.0 | 支持:6.0 | 支持:1.0 |
支持回調(diào)函數(shù)[1] | ? | ? | ? | ? | ? | ? | ? |
限制跟蹤超時腳本 | ? | ? | ? | 支持:55.0 | ? | ? | ? |
注釋:
[1]它是否支持第一種形式的可選參數(shù)。
[2] setTimeout() 現(xiàn)在在 WindowOrWorkerGlobalScope mixin 上定義。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: