(转自:http://www.mxria.com/helps/js_error/trap_error_1572.htm)异步
因为 JavaScript 是异步的,可使用 setTimeout
和 setInterval
来计划执行函数。函数
注意:定时处理不是ECMAScript 的标准,它们在 DOM (文档对象模型) 被实现。this
function foo(){}var id = setTimeout(foo,1000);// 返回一个大于零的数字
当 setTimeout
被调用时,它会返回一个 ID 标识而且计划在未来大约1000 毫秒后调用 foo
函数。 foo
函数只会被执行一次。spa
基于 JavaScript 引擎的计时策略,以及本质上的单线程运行方式,因此其它代码的运行可能会阻塞此线程。 所以无法确保函数会在 setTimeout
指定的时刻被调用。线程
做为第一个参数的函数将会在全局做用域中执行,所以函数内的 this
将会指向这个全局对象。code
functionFoo(){this.value =42;this.method =function(){// this 指向全局对象 console.log(this.value);// 输出:undefined}; setTimeout(this.method,500);}newFoo();
注意:setTimeout
的第一个参数是函数对象,一个常犯的错误是这样的 setTimeout(foo(), 1000)
, 这里回调函数是 foo
的返回值,而不是foo
自己。 大部分状况下,这是一个潜在的错误,由于若是函数返回 undefined
,setTimeout
也不会报错。htm
setInterval
的堆调用setTimeout
只会执行回调函数一次,不过 setInterval
- 正如名字建议的 - 会每隔 X
毫秒执行函数一次。 可是却不鼓励使用这个函数。对象
当回调函数的执行被阻塞时,setInterval
仍然会发布更多的毁掉指令。在很小的定时间隔状况下,这会致使回调函数被堆积起来。ip
function foo(){// 阻塞执行 1 秒} setInterval(foo,1000);
上面代码中,foo
会执行一次随后被阻塞了一分钟。作用域
在 foo
被阻塞的时候,setInterval
仍然在组织未来对回调函数的调用。 所以,当第一次 foo
函数调用结束时,已经有10次函数调用在等待执行。
最简单也是最容易控制的方案,是在回调函数内部使用 setTimeout
函数。
function foo(){// 阻塞执行 1 秒 setTimeout(foo,1000);} 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,而后一把清除。
eval
setTimeout
和 setInterval
也接受第一个参数为字符串的状况。 这个特性绝对不要使用,由于它在内部使用了 eval
。
注意:因为定时器函数不是 ECMAScript 的标准,如何解析字符串参数在不一样的 JavaScript 引擎实现中可能不一样。 事实上,微软的 JScript 会使用 Function
构造函数来代替 eval
的使用。
function foo(){// 将会被调用}function bar(){function foo(){// 不会被调用} setTimeout('foo()',1000);} bar();
因为 eval
在这种状况下不是被直接调用,所以传递到 setTimeout
的字符串会自全局做用域中执行; 所以,上面的回调函数使用的不是定义在 bar
做用域中的局部变量 foo
。
建议不要在调用定时器函数时,为了向回调函数传递参数而使用字符串的形式。
function foo(a, b, c){}// 不要这样作 setTimeout('foo(1,2, 3)',1000)// 可使用匿名函数完成相同功能 setTimeout(function(){ foo(a, b, c);},1000)
注意:虽然也可使用这样的语法 setTimeout(foo, 1000, a, b, c)
, 可是不推荐这么作,由于在使用对象的属性方法时可能会出错。 (译者注:这里说的是属性方法内,this
的指向错误)
绝对不要使用字符串做为 setTimeout
或者 setInterval
的第一个参数, 这么写的代码明显质量不好。当须要向回调函数传递参数时,能够建立一个匿名函数,在函数内执行真实的回调函数。
另外,应该避免使用 setInterval
,由于它的定时执行不会被 JavaScript 阻塞