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