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

由于 Javascript 是异步的,因而我们能够经由过程 setTimeoutsetInterval 函数来指定特定时候实行代码。

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

上例中,当 setTimeout 函数被挪用时,它会返回一个标志延时的 ID 并计划在约莫 1000 毫秒后挪用 foo 函数,函数 foo 将只会实行一次。
依据 Javascript 引擎的计时要领,以及 Javascript 单线程的实质,因而其他代码实行时能够会壅塞此线程,我们没法保证 setTimeout 函数内挪用的函数会在指定的时候被实行。
setTimeout 函数的第一个参数将会在全局作用域内实行,因而参数内的 this 将会指向全局对象。

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 函数依旧会继承挪用更多的回调函数。当间隔时候设置较小时,将会致使回调函数聚集。

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 函数如今能够本身掌握是不是继承或停止。

手动消灭定时器

消灭定时器能够经由过程通报指定的 IDclearTimeoutclearInterval 函数。

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

消灭一切的定时器

Javascript 中并没有内置的函数要领来消灭一切的定时器(timeoutinterval),不过我们能够运用一种暴力的要领来消灭一切的定时器。

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

然则很明显,由于指定最大值的限定,还会有定时器没有被消灭掉。由于 ID 会跟着定时器被挪用的增添而增添,因而更好的要领是记录下最大的 ID 并一同消灭。

// 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 都进修了一遍,基本上每个章节都翻译了一遍,同时加上了本身的一些主意和笔记,也许花了半个多月的时候,觉得这的确实确是个很合适本身的进修要领,有时候遗忘某些观点,我立马就可以在本身的博客中找到相干的学问并实时回想,由于出自本身的笔下,所以很快就可以回想起来。愿望本身能对峙这个好的习气,也愿望本身的博文能给博友们带来些许的协助,人人互相进修,共同进步!

    原文作者:StephenLee
    原文地址: https://segmentfault.com/a/1190000000517177
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞