有人问我(一个朋友)建立一个定时器(无限其中之一写入一行每秒),但没有setInterval
。
我解决它:
var i = 0;
function k(myId, cb)
{
setTimeout(function ()
{
console.log(myId);
cb();
}, 1000);
}
function go()
{
i++;
k(i, go);
}
go();
而且这是工作。
问题是,恐怕会是一个内存压力。 实际上,它创建了一个递归和(周或某事),经过一段时间 - 的过程中会消耗大量的内存。 (堆被永远不会释放)
我怎样才能改变我的代码,以便没有多大的内存消耗?
这不是递归
它可能看起来像递归,但setTimeout的不创建递归。
setTimeout的工作方式是,它立即返回。 所以调用k
结束立即用它的堆栈释放。
当超时实际发生,并调用go
再次发生它是不是从以前调用点k
但是从全球范围内*。
*注:我没有使用在规范的ECMAScript这里定义的范围严格意义。 我的意思是将呼叫k
将被搞得好像你在一个普通的写它<script></script>
标签:也就是说,任何其他函数调用之外。
对于在关闭您的关注
在特定情况下,有这其实包含在被创建的闭包很少k
功能。 唯一显著闭包是参考参数cb
和myId
。 而且即便如此,它仅持续约一秒钟:
#1 function k(myId, cb) {
#2 setTimeout(function(){
#3 console.log(myId); // there is a closure here to myId
#4 cb(); // and another one for cb
#5
/* But at this point in the function, setTimeout ends
* and as the function returns, there are no remaining
* references to either "cb" or "myId" accessible
* anywhere else. Which means that the GC can immediately
* free them (though in reality the GC may run a bit later)
*/
#6 }, 1000); // So one second is roughly the longest the closure lasts
}
比这更简单
我要指出,你的代码是相当令人费解。 它可以写简单,且无需在所有使用闭包(减去全局变量i)如果你只是把它写这样的:
// Simpler, does exactly the same thing:
var i = 0;
function go () {
console.log(i);
i++;
setTimeout(go, 1000); // callback
}
go();
这条线是假的:
实际上,它创建了一个递归和(周或某事),经过一段时间 - 的过程中会消耗大量的内存。 (堆被永远不会释放)
它不会产生递归,因为该功能完全退出,然后再调用。
递归堆叠在彼此的顶部
function a() {a()}; // function calls itself until a stack overflow.
堆栈看起来是这样的
a()
a()
a()
a() ... until a crash.
随着setTimeout的,你执行一个功能。 这个函数设置功能再次运行一个事件 - 但这里是重要的区别:函数退出,完整,没有了[1]。 然后,它再次调用。
执行明智的,它是不是从这样做太大的不同:
function a() {console.log("I am called");}
a(); // Call the function;
a(); // Call the function again
a(); // Call the function again
setTimeout
只是给浏览器有机会“呼吸”如果你愿意。 用于屏幕更新的机会,其他事件来处理。 它不,使用正确的术语, block
浏览器。
这不会产生内存泄漏。
事实上,这是一个非常常用的概念。 通常它会出现在这种形式:
setTimeout(function next() {
// Do something...
// Have the function set another timeout to call itself later.
setTimeout(next, 10);
}, 10);
当您要检查的东西往往(这里每10毫秒),它可以更好地使用这种模式,而不是setInterval
,因为它可以提高你的页面的性能。 举例来说,如果你的函数需要超过10毫秒来执行,并且您使用setInterval(f, 10)
那么它将被不断地被调用。 但是,如果您使用setTimeout
上面的图案,这将至少确保处理器得到每个调用之间的10毫秒的突破,无论你的功能需要多长时间来执行。
见保罗爱尔兰这个视频(始于7:46)关于该模式的更多信息。