setTimeout和setInterval:
- 指定延迟后调用函数,
- 以指定周期调用函数
让我们想象一个意外情况,比如说下面的setInterval
setInterval(function () {
func(i++);
}, 100)
我们每100毫秒调用一次func函数,如果func的执行时间少于100毫秒的话,在遇到下一个100毫秒前就能够执行完:
;
但如果func的执行时间大于100毫秒,该触发下一个func函数时之前的还没有执行完怎么办?答案如下图所示,那么第二个func会在队列(这里的队列是指event loop)中等待,直到第一个函数执行完
;
如果第一个函数的执行时间特别长,在执行的过程中本应触发了许多个func怎么办,那么所有这些应该触发的函数都会进入队列吗?
不,只要发现队列中有一个被执行的函数存在,那么其他的统统忽略。如下图,在第300毫秒和400毫秒处的回调都被抛弃,一旦第一个函数执行完后,接着执行队列中的第二个,即使这个函数已经“过时”很久了。
;
还有一点,虽然你在setInterval的里指定的周期是100毫秒,但它并不能保证两个函数之间调用的间隔一定是一百毫秒。在上面的情况中,如果队列中的第二个函数时在第450毫秒处结束的话,在第500毫秒时,它会继续执行下一轮func,也就是说这之间的间隔只有50毫秒,而非周期100毫秒
那如果我想保证每次执行的间隔应该怎么办?用setTimeout,比如下面的代码:
var i = 1
var timer = setTimeout(function() {
alert(i++)
timer = setTimeout(arguments.callee, 2000)
}, 2000)
上面的函数每2秒钟递归调用自己一次,你可以在某一次alert的时候等待任意长的时间(不按“确定”按钮),接下来无论你什么时候点击“确定”, 下一次执行一定离这次确定相差2秒钟的
setTimeout(function repeatMe() {
/* Some long block of code... */
setTimeout(repeatMe, 10);
}, 10);
setInterval(function() {
/* Some long block of code... */
}, 10);
比如说:在处理DOM点击事件的时候通常会产生冒泡,正常情况下首先触发的是子元素的handler,再触发父元素的handler,如果我想让父元素的handler先于子元素的handler执行应该怎么办?那就用setTimeout延迟子元素handler若干个毫秒执行吧。问题是这个“若干个”毫秒应该是多少?可以是0
你可能会疑惑如果是0的话那不是立即执行了吗?不,看下面一道题目
(function () {
setTimeout(function () {
alert(2);
}, 0);
alert(1);
})()
先弹出的应该是1,而不是你以为“立即执行”的2。