Javascript 我可以使用setTimeout创建一个便宜的无限循环吗?

Javascript 我可以使用setTimeout创建一个便宜的无限循环吗?,javascript,node.js,functional-programming,memory-management,Javascript,Node.js,Functional Programming,Memory Management,这段代码让我烦恼的是我传递了8000次字符串。这会导致任何类型的内存问题吗 另外,如果我使用node.js运行此代码,它会立即打印,这不是我所期望的。如果您担心字符串被复制8000次,请不要担心,字符串只有一个副本;传递的是引用 更大的问题是,调用函数时创建的对象(称为“执行上下文”的“变量绑定对象”)是否会被保留,因为您正在创建一个闭包,该闭包对上下文的变量对象具有引用,因此只要闭包仍在某处被引用,该对象就会保留在内存中 答案是:是的,但只有在计时器启动之前,因为一旦它执行任何操作,就不再引用

这段代码让我烦恼的是我传递了8000次字符串。这会导致任何类型的内存问题吗


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

如果您担心字符串被复制8000次,请不要担心,字符串只有一个副本;传递的是引用

更大的问题是,调用函数时创建的对象(称为“执行上下文”的“变量绑定对象”)是否会被保留,因为您正在创建一个闭包,该闭包对上下文的变量对象具有引用,因此只要闭包仍在某处被引用,该对象就会保留在内存中

答案是:是的,但只有在计时器启动之前,因为一旦它执行任何操作,就不再引用闭包,因此垃圾收集器可以同时回收它们。所以你不会有8000个优秀的,只有一两个。当然,GC何时以及如何运行取决于实现


奇怪的是,就在今天早些时候,我们讨论了一个非常相似的话题;也请参见此处。

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

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

如果要在节点中创建异步循环,可以使用
process.nextTick
。它将比一般Javascript中的setTimeout(func,1)

更快,因此编写递归代码通常会有导致堆栈溢出的风险。如果像这样使用
setTimeout
,它会有效地重置调用堆栈,因此堆栈溢出不再是问题


但是性能将是个问题,因为每次调用
setTimeout
通常都需要相当长的时间(大约10毫秒),即使您将
delay
设置为0。

的“1”是1毫秒。这也可能是一个for循环。1秒等于1000。我最近写了一些类似的东西,检查后端一批进程的进度,并将延迟设置为500。如果我没记错的话,旧的浏览器看不到1到15毫秒之间有什么真正的区别。我认为V8实际上可能处理得更快

我认为在最后一次迭代完成之前,不会对任何函数进行垃圾收集,但这些新一代的JS JIT编译器比我了解更多的编译器要聪明得多,因此它们可能会看到超时后没有发生任何事情,并从内存中提取这些参数

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

防止内存密集型参数出现潜在问题的一种方法是,传入具有所需参数的对象。那么我相信params只是对内存中某个设置位置的引用

比如:

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

将超时设置为1(实际上小于30左右)会导致浏览器在主循环的下一次迭代中只执行该函数。@Emil:它因实现而异。有些实现不允许您将延迟设置为小于5或10,即使循环早于5或10。或者我被告知,我还没有亲自去查看源代码。我自己编辑的逻辑错误。从技术上来说,这是一个终结吗?我不确定在递归场景中如何处理链式参数。此外,互联网似乎无法就关闭的定义达成一致。不过,我总的想法是把你的脚伸进范围完成的大门。@Erik:是的,从技术上讲,这是一个终结(更多:)。:-)这使用了旧的第三版规范术语,但您仍然可以遵循它。在更广泛的计算(和数学)领域,“闭包”是一个通用术语,用于表示一个函数,该函数的数据本质上与之绑定。在JavaScript中,绑定的数据是对创建函数的作用域链顶部的变量绑定对象的引用(该对象有一个指向VBO的链接,用于上一个执行上下文,如果有的话,等等)。
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--