我可以使用setTimeout创build一个廉价的无限循环?

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次的string。 这是否会导致任何types的内存问题?

另外,如果我用node.js运行这个代码,它立即打印,这不是我所期望的。

如果你担心string被复制8000次,不要这样,只有一个string的副本; 传递的是一个参考。

更大的问题是,当您调用一个函数(称为“执行上下文”的“variables绑定对象”)时是否保留了该对象,因为您正在创build一个闭包,并且该variables对象具有对上下文,因此只要闭包仍然在某个地方被引用,它就会将其保存在内存中。

答案是:是的,但只有在定时器触发之前,因为一旦它不再引用闭包,垃圾收集器就可以收回它们。 所以你不会有8,000个优秀的,只有一两个。 当然,GC何时以及如何运行取决于实施。

奇怪的是,就在今天早些时候,我们还有一个非常类似的话题。 在那里也可以看到我的回答 。

它立即打印,因为程序执行“立即”。 在我的Intel i5机器上,根据time node test.js ,整个操作需要time node test.js

对于内存问题,这是一个“廉价的无限循环”,你只需要进行实验和测量。

如果你想在节点中创build一个asynchronous循环,你可以使用process.nextTick 。 它会比setTimeout(func, 1)更快。

通常,Javascript 不支持尾部调用优化 ,因此编写recursion代码通常会导致堆栈溢出。 如果像这样使用setTimeout ,它将有效地重置调用堆栈,所以堆栈溢出不再是一个问题。

性能将成为问题,因为每次调用setTimeout通常需要一段时间(大约10毫秒),即使将delay设置为0也是如此。

“1”是1毫秒。 这可能是一个for循环。 1秒是1000.我最近写了一些类似的检查后端批处理的进度,并设置了500的延迟。如果我没有记错的话,老的浏览器在1到15ms之间看不到任何实际的差异。 我认为V8实际上可能比这个更快。

我不认为垃圾收集会发生在任何函数上,直到最后一次迭代完成,但这些新一代的JS JIT编译器比我更了解的更聪明,所以有可能他们会看到没有任何东西在超时之后真的在继续,并从记忆中拉出这些参数。

无论如何,即使为这些参数的每个实例保留了内存,也需要超过8000次迭代才能产生问题。

用更多的内存密集型参数来防范潜在的问题的一种方法是,如果你传递一个你想要的参数的对象。 那么我相信这些参数只是提及一个记忆的地方。

所以像这样:

 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--