setTimeout 和 setInterval
由于 JavaScript 是異步的,可以使用?setTimeout?和?setInterval?來(lái)計(jì)劃執(zhí)行函數(shù)。
注意:?定時(shí)處理不是ECMAScript 的標(biāo)準(zhǔn),它們?cè)贒OM (文檔對(duì)象模型)?被實(shí)現(xiàn)。
function foo() {} var id = setTimeout(foo, 1000); // 返回一個(gè)大于零的數(shù)字當(dāng)?setTimeout?被調(diào)用時(shí),它會(huì)返回一個(gè) ID 標(biāo)識(shí)并且計(jì)劃在將來(lái)大約?1000 毫秒后調(diào)用?foo?函數(shù)。?foo?函數(shù)只會(huì)被執(zhí)行一次。
基于 JavaScript 引擎的計(jì)時(shí)策略,以及本質(zhì)上的單線程運(yùn)行方式,所以其它代碼的運(yùn)行可能會(huì)阻塞此線程。 因此沒(méi)法確保函數(shù)會(huì)在?setTimeout?指定的時(shí)刻被調(diào)用。
作為第一個(gè)參數(shù)的函數(shù)將會(huì)在全局作用域中執(zhí)行,因此函數(shù)內(nèi)的?this?將會(huì)指向這個(gè)全局對(duì)象。
function Foo() {this.value = 42;this.method = function() {// this 指向全局對(duì)象console.log(this.value); // 輸出:undefined};setTimeout(this.method, 500); } new Foo();注意:?setTimeout?的第一個(gè)參數(shù)是函數(shù)對(duì)象,一個(gè)常犯的錯(cuò)誤是這樣的setTimeout(foo(), 1000), 這里回調(diào)函數(shù)是?foo?的返回值,而不是foo本身。 大部分情況下,這是一個(gè)潛在的錯(cuò)誤,因?yàn)槿绻瘮?shù)返回undefined,setTimeout?也不會(huì)報(bào)錯(cuò)。
setInterval?的堆調(diào)用
setTimeout?只會(huì)執(zhí)行回調(diào)函數(shù)一次,不過(guò)?setInterval?- 正如名字建議的 - 會(huì)每隔?X?毫秒執(zhí)行函數(shù)一次。 但是卻不鼓勵(lì)使用這個(gè)函數(shù)。
當(dāng)回調(diào)函數(shù)的執(zhí)行被阻塞時(shí),setInterval?仍然會(huì)發(fā)布更多的回調(diào)指令。在很小的定時(shí)間隔情況下,這會(huì)導(dǎo)致回調(diào)函數(shù)被堆積起來(lái)。
function foo(){// 阻塞執(zhí)行 1 秒 } setInterval(foo, 100);上面代碼中,foo?會(huì)執(zhí)行一次隨后被阻塞了一秒鐘。
在?foo?被阻塞的時(shí)候,setInterval?仍然在組織將來(lái)對(duì)回調(diào)函數(shù)的調(diào)用。 因此,當(dāng)?shù)谝淮?foo?函數(shù)調(diào)用結(jié)束時(shí),已經(jīng)有?10?次函數(shù)調(diào)用在等待執(zhí)行。
處理可能的阻塞調(diào)用
最簡(jiǎn)單也是最容易控制的方案,是在回調(diào)函數(shù)內(nèi)部使用?setTimeout?函數(shù)。
function foo(){// 阻塞執(zhí)行 1 秒setTimeout(foo, 100); } foo();這樣不僅封裝了?setTimeout?回調(diào)函數(shù),而且阻止了調(diào)用指令的堆積,可以有更多的控制。?foo?函數(shù)現(xiàn)在可以控制是否繼續(xù)執(zhí)行還是終止執(zhí)行。
手工清空定時(shí)器
可以通過(guò)將定時(shí)時(shí)產(chǎn)生的 ID 標(biāo)識(shí)傳遞給?clearTimeout?或者?clearInterval函數(shù)來(lái)清除定時(shí), 至于使用哪個(gè)函數(shù)取決于調(diào)用的時(shí)候使用的是?setTimeout還是?setInterval。
var id = setTimeout(foo, 1000); clearTimeout(id);清除所有定時(shí)器
由于沒(méi)有內(nèi)置的清除所有定時(shí)器的方法,可以采用一種暴力的方式來(lái)達(dá)到這一目的。
// 清空"所有"的定時(shí)器 for(var i = 1; i < 1000; i++) {clearTimeout(i); }可能還有些定時(shí)器不會(huì)在上面代碼中被清除(譯者注:如果定時(shí)器調(diào)用時(shí)返回的 ID 值大于 1000), 因此我們可以事先保存所有的定時(shí)器 ID,然后一把清除。
隱藏使用?eval
setTimeout?和?setInterval?也接受第一個(gè)參數(shù)為字符串的情況。 這個(gè)特性絕對(duì)不要使用,因?yàn)樗趦?nèi)部使用了?eval。
注意:?由于定時(shí)器函數(shù)不是 ECMAScript 的標(biāo)準(zhǔn),如何解析字符串參數(shù)在不同的 JavaScript 引擎實(shí)現(xiàn)中可能不同。 事實(shí)上,微軟的 JScript 會(huì)使用?Function?構(gòu)造函數(shù)來(lái)代替?eval?的使用。
function foo() {// 將會(huì)被調(diào)用 }function bar() {function foo() {// 不會(huì)被調(diào)用}setTimeout('foo()', 1000); } bar();由于?eval?在這種情況下不是被直接調(diào)用,因此傳遞到?setTimeout?的字符串會(huì)自全局作用域中執(zhí)行; 因此,上面的回調(diào)函數(shù)使用的不是定義在?bar?作用域中的局部變量?foo。
建議不要在調(diào)用定時(shí)器函數(shù)時(shí),為了向回調(diào)函數(shù)傳遞參數(shù)而使用字符串的形式。
function foo(a, b, c) {}// 不要這樣做 setTimeout('foo(1,2, 3)', 1000)// 可以使用匿名函數(shù)完成相同功能 setTimeout(function() {foo(1, 2, 3); }, 1000)注意:?雖然也可以使用這樣的語(yǔ)法?setTimeout(foo, 1000, 1, 2, 3), 但是不推薦這么做,因?yàn)樵谑褂脤?duì)象的屬性方法時(shí)可能會(huì)出錯(cuò)。 (譯者注:這里說(shuō)的是屬性方法內(nèi),this?的指向錯(cuò)誤)
結(jié)論
絕對(duì)不要使用字符串作為?setTimeout?或者?setInterval?的第一個(gè)參數(shù), 這么寫的代碼明顯質(zhì)量很差。當(dāng)需要向回調(diào)函數(shù)傳遞參數(shù)時(shí),可以創(chuàng)建一個(gè)匿名函數(shù),在函數(shù)內(nèi)執(zhí)行真實(shí)的回調(diào)函數(shù)。
另外,應(yīng)該避免使用?setInterval,因?yàn)樗亩〞r(shí)執(zhí)行不會(huì)被 JavaScript 阻塞。
轉(zhuǎn)載于:https://www.cnblogs.com/luckyxb/p/6398574.html
總結(jié)
以上是生活随笔為你收集整理的setTimeout 和 setInterval的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: WCF、WebAPI、WCFREST、W
- 下一篇: 关于wordpress 点击文章查看内容