我可以使用setTimeout创建一个廉价的无限循环吗
Can I use setTimeout to create a cheap infinite loop?
var recurse = function(steps, data, delay) {
if(steps == 0) {
console.log(data.length)
} else {
setTimeout(function(){
recurse(steps - 1, data, delay);
}, delay);
}
};
var myData = "abc";
recurse(8000, myData, 1);
这段代码让我感到困扰的是,我传递了8000次字符串。这会导致任何类型的记忆问题吗?
此外,如果我用node.js运行这段代码,它会立即打印出来,这不是我所期望的。
如果你担心字符串被复制8000次,不要担心,字符串只有一个副本;传递的是一个参考。
更大的问题是,当你调用一个函数时创建的对象(称为"执行上下文"的"变量绑定对象"(是否会被保留,因为你正在创建一个闭包,并且它对上下文的变量对象有引用,因此只要闭包仍在某个地方被引用,它就会保留在内存中。
答案是:是的,但只有在计时器触发之前,因为一旦它不做任何事情,就不再引用闭包,因此垃圾收集器可以回收它们。所以你不会有8000个优秀的,只有一两个。当然,GC何时以及如何运行取决于实现。
奇怪的是,就在今天早些时候,我们就一个非常相似的话题提出了另一个问题;在那里也可以看到我的答案。
它会立即打印,因为程序会"立即"执行。根据time node test.js
,在我的英特尔i5机器上,整个操作需要0.07s。
对于内存问题,以及这是否是一个"廉价的无限循环",你只需要进行实验和测量。
若要在节点中创建异步循环,可以使用process.nextTick
。它将比setTimeout(func, 1)
更快。
通常,Javascript不支持尾部调用优化,因此编写递归代码通常会有导致堆栈溢出的风险。如果像这样使用setTimeout
,它可以有效地重置调用堆栈,因此堆栈溢出不再是问题。
不过,性能将是个问题,因为即使将delay
设置为0,对setTimeout
的每次调用通常也需要相当长的时间(约10ms(。
"1"是1毫秒。这可能是一个for循环。1秒是1000。我最近在后端写了一些类似的检查一批进程进度的内容,并设置了500的延迟。如果我没记错的话,旧的浏览器在1到15毫秒之间不会看到任何真正的区别。我认为V8实际上可能处理得比这更快。
我认为在上一次迭代完成之前,垃圾收集不会发生在任何函数上,但这些新一代的JS JIT编译器比我更了解的编译器聪明得多,所以他们可能会看到超时后什么都没有发生,并从内存中提取这些参数。
无论如何,即使为这些参数的每个实例保留了内存,也需要8000多次迭代才能产生问题。
使用内存密集型参数防止潜在问题的一种方法是,如果您传入一个具有所需参数的对象。那么我相信params将只是对记忆中某个固定位置的引用。
所以类似于:
var recurseParams ={ steps:8000, data:"abc", delay:100 } //outside of the function
//define the function
recurse(recurseParams);
//Then inside the function reference like this:
recurseParams.steps--
- 为什么我使用javascript获得了一个无限的for循环
- javascript停止一个无限循环
- setTimeout 会创建一个无限循环
- 为什么我有一个无限循环
- 为什么(;;){…}是一个无限循环
- 为什么“;window=window.parent"创建一个无限循环
- 把我的折线放在一个无限循环中
- 为什么这个树的布局给了我一个无限的循环
- JavaScript:为什么这会导致一个无限循环
- 两个同步事件创建了一个无限循环
- 为什么我的javascript代码会进入一个无限循环
- 为什么这会导致一个无限循环
- 在一个无限循环风格的展示中预先加载相邻的条目
- addEventListener创建了一个无限循环
- 在Jquery中创建一个无限循环
- 为什么这段代码创建了一个无限循环?
- Select2 trigger("change")创建一个无限循环
- 为什么这会产生一个无限循环
- 是否有任何解决方案来结束一个无限循环函数
- 为什么我的角脚本运行一个无限循环