细说 Javascript 拾遗篇(四) : setTimeout 和 setInterval

因为 Javascript 是异步的,所以咱们能够经过 setTimeoutsetInterval 函数来指定特定时间执行代码。git

function foo() {}
var id = setTimeout(foo, 1000); // returns a Number > 0

上例中,当 setTimeout 函数被调用时,它会返回一个标志延时的 ID 并计划在大约 1000 毫秒后调用 foo 函数,函数 foo 将只会执行一次。
根据 Javascript 引擎的计时方法,以及 Javascript 单线程的本质,所以其余代码执行时可能会阻塞此线程,咱们没法保证 setTimeout 函数内调用的函数会在指定的时间被执行。
setTimeout 函数的第一个参数将会在全局做用域内执行,所以参数内的 this 将会指向全局对象。github

function Foo() {
    this.value = 42;
    this.method = function() {
        // this refers to the global object
        console.log(this.value); // will log undefined
    };
    setTimeout(this.method, 500);
}
new Foo();

这里要注意一个常犯的错误,setTimeout 函数的第一个参数指的是函数对象自己,不能写成相似 setTimeout(foo(), 1000),由于 foo() 是函数返回值,而不是 foo 自己。异步

setInterval 函数的堆调用

从上文已知,setTimeout 中的回调函数只会执行一次,而 setInterval 函数,正如函数的名字同样,它会每隔指定时间执行一次回调函数。
即便回调函数的执行被阻塞,setInterval 函数依然会继续调用更多的回调函数。当间隔时间设置较小时,将会致使回调函数堆积。ide

function foo(){
    // something that blocks for 1 second
}
setInterval(foo, 1000);

上述代码中,函数 foo 被调用后将被阻塞一秒钟。函数

处理可能阻塞的代码

最简单且最可控的方式就是在回调函数内部使用 setTimeout 函数。学习

function foo(){
    // something that blocks for 1 second
    setTimeout(foo, 1000);
}
foo();

这样不只封装了 setTimeout 的调用,同时也阻止了可能存在的回调函数堆积。foo 函数如今能够本身控制是否继续或终止。this

手动清除定时器

清除定时器能够经过传递指定的 IDclearTimeoutclearInterval 函数。线程

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

清除全部的定时器

Javascript 中并无内置的函数方法来清除全部的定时器(timeoutinterval),不过咱们能够使用一种暴力的方法来清除全部的定时器。翻译

// clear "all" timeouts
for(var i = 1; i < 1000; i++) {
    clearTimeout(i);
}

可是很明显,因为指定最大值的限制,还会有定时器没有被清除掉。因为 ID 会随着定时器被调用的增长而增长,所以更好的方法是记录下最大的 ID 并一块儿清除。code

// clear "all" timeouts
var biggestTimeoutId = window.setTimeout(function(){}, 1),
i;
for(i = 1; i <= biggestTimeoutId; i++) {
    clearTimeout(i);
}

eval 的隐式使用

setTimeoutsetInterval 函数的第一个参数也能够接收字符串,可是尽可能不要使用这个功能,由于这会在内部调用 eval 函数来执行这段字符串。

function foo() {
    // will get called
}

function bar() {
    function foo() {
        // never gets called
    }
    setTimeout('foo()', 1000);
}
bar();

因为 eval 函数并无在上例中被直接调用,所以传递到 setTimeout 函数的字符串将会在全局做用域下被执行,因此不会调用函数 bar 内部的 foo 函数。
建议尽可能不要在使用定时器函数时经过字符串形式来传递参数。

function foo(a, b, c) {}

// NEVER use this
setTimeout('foo(1, 2, 3)', 1000)

// Instead use an anonymous function
setTimeout(function() {
    foo(a, b, c);
}, 1000)

总结

不要使用字符串做为 setTimeoutsetInterval 函数的参数,当须要向回调函数中传递参数时,咱们能够用匿名函数的,在匿名函数内部执行回调函数。
另外,尽可能避免使用 setInterval 函数,从而避免可能致使的回调函数堆积现象。

参考

http://bonsaiden.github.io/JavaScript-Garden/#other.timeouts

后言

终于将整个 Javascript Garden 都学习了一遍,基本上每个章节都翻译了一遍,同时加上了本身的一些想法和笔记,大概花了半个多月的时间,感受这的的确确是个很适合本身的学习方法,有时候忘记某些概念,我立马就能在本身的博客中找到相关的知识并及时回顾,因为出自本身的笔下,因此很快就能回忆起来。但愿本身能坚持这个好的习惯,也但愿本身的博文能给博友们带来些许的帮助,你们相互学习,共同进步!

相关文章
相关标签/搜索