高性能setTimeout 和 setInterval

由于 JavaScript 是异步的,可以使用 setTimeout 和 setInterval 来计划执行函数。

注意: 定时处理不是ECMAScript 的标准,它们在DOM (文档对象模型) 被实现。

function foo()
{
}
var id = setTimeout(foo, 1000); // 返回一个大于零的数字

当 setTimeout 被调用时,它会返回一个 ID 标识并且计划在将来大约 1000 毫秒后调用 foo 函数。 foo 函数只会被执行一次

基于 JavaScript 引擎的计时策略,以及本质上的单线程运行方式,所以其它代码的运行可能会阻塞此线程。 因此没法确保函数会在 setTimeout 指定的时刻被调用。

作为第一个参数的函数将会在全局作用域中执行,因此函数内的 this 将会指向这个全局对象。

function Foo() {
     this.value = 42;     
     this.method = function() {
         // this 指向全局对象
         console.log(this.value); // 输出:undefined
     };
     setTimeout(this.method, 500);
 } 
new Foo();

注意: setTimeout 的第一个参数是函数对象,一个常犯的错误是这样的setTimeout(foo(), 1000), 这里回调函数是 foo返回值,而不是foo本身。 大部分情况下,这是一个潜在的错误,因为如果函数返回undefinedsetTimeout不会报错。

setInterval 的堆调用

setTimeout 只会执行回调函数一次,不过 setInterval - 正如名字建议的 – 会每隔 X 毫秒执行函数一次。 但是却不鼓励使用这个函数。

当回调函数的执行被阻塞时,setInterval 仍然会发布更多的毁掉指令。在很小的定时间隔情况下,这会导致回调函数被堆积起来。

function foo(){
     // 阻塞执行 1 秒
 } 
setInterval(foo, 100);

上面代码中,foo 会执行一次随后被阻塞了一分钟。

在 foo 被阻塞的时候,setInterval 仍然在组织将来对回调函数的调用。 因此,当第一次 foo 函数调用结束时,已经有 10 次函数调用在等待执行。

处理可能的阻塞调用

最简单也是最容易控制的方案,是在回调函数内部使用 setTimeout 函数。

function foo(){ 
    // 阻塞执行 1 秒
     setTimeout(foo, 100);
 }
 foo();

这样不仅封装了 setTimeout 回调函数,而且阻止了调用指令的堆积,可以有更多的控制。 foo 函数现在可以控制是否继续执行还是终止执行。

手工清空定时器

可以通过将定时时产生的 ID 标识传递给 clearTimeout 或者 clearInterval函数来清除定时, 至于使用哪个函数取决于调用的时候使用的是 setTimeout还是 setInterval

var id = setTimeout(foo, 1000);
 clearTimeout(id);

清除所有定时器

由于没有内置的清除所有定时器的方法,可以采用一种暴力的方式来达到这一目的。

// 清空"所有"的定时器
 for(var i = 1; i < 1000; i++) {
     clearTimeout(i);
 }

可能还有些定时器不会在上面代码中被清除(译者注如果定时器调用时返回的 ID 值大于 1000), 因此我们可以事先保存所有的定时器 ID,然后一把清除。

 

http://www.exiatian.com/%E9%AB%98%E6%80%A7%E8%83%BDsettimeout-%E5%92%8C-setinterval/

posted @ 2014-08-07 14:58  Shimily  阅读(825)  评论(0)    收藏  举报