简体   繁体   English

Javascript:settimeout 递归无限堆栈增加?

[英]Javascript: settimeout recursion endless stack increase?

My goal is a slideshow of background images with HTML/CSS/JS.我的目标是使用 HTML/CSS/JS 制作背景图片的幻灯片。 Many solutions that I've found promote something like this:我发现的许多解决方案都促进了这样的事情:

my_recursion();

function my_recursion () {
 // cycle the Background image ...
 setTimeout(my_recursion, 3000);
}

Am I wrong to assume that this is bad style?我认为这是不好的风格是错误的吗? I would expect that at eg cycle 1000 all the other 999 instances of my_recursion are still open / on the stack?我希望在例如周期 1000 时,所有其他 999 个 my_recursion 实例仍然打开/在堆栈上? Doesn't this create and infinite stack which consumes more and more memory?这不会创建消耗越来越多内存的无限堆栈吗?

Or is there some sort of intelligence involved which does something like "if a function calls itself at the end, the (n-1)th function is destroyed including all variables that were assigned inside of it"?或者是否涉及某种智能,例如“如果一个函数在最后调用自己,则第 (n-1) 个函数将被销毁,包括在其中分配的所有变量”?

This will not result in endless stack increase, because of the way setTimeout works, and imho it is not bad style.这不会导致无休止的堆栈增加,因为 setTimeout 的工作方式,恕我直言,它的风格还不错。

setTimeout does not guarantee that code will run directly after the given timeout. setTimeout不保证代码会在给定的超时后直接运行。 Instead, after that timeout it will push the callback onto a "queue", which will be processed when the stack is empty.相反,在超时之后,它会将回调推送到“队列”上,当堆栈为空时将对其进行处理。 So it will only run when my_recursion has returned and the stack is empty.所以它只会在 my_recursion 返回并且堆栈为空时运行。

If a function calls itself at the end (...)如果一个函数在最后调用自己 (...)

my_recursion doesn't call itself anywhere. my_recursion不会在任何地方调用自己。 It just passes itself as an argument to setTimeout .它只是将自己作为参数传递给setTimeout After that, it will just continue executing, return directly after, and will be popped from the stack.之后,它会继续执行,之后直接返回,并从堆栈中弹出。

This presentation explains the stack and the event queue.本演示文稿解释了堆栈和事件队列。

In your question, your function does not have any parameters.在您的问题中,您的函数没有任何参数。 In a real implementation, I hope you plan to use them.在实际实现中,我希望您计划使用它们。

 const cycleBackground = (elem, bgs = [], ms = 1e3, i = 0) => ( elem.setAttribute ('style', bgs[i]) , setTimeout ( cycleBackground // function to schedule , ms // when to schedule, ms from now , elem // user-specified element to change , bgs // user-specified backgrounds , ms // user-specified delay , (i + 1) % bgs.length // next background index ) ) const backgrounds = [ "background-color: red;" , "background-image: linear-gradient(45deg, cyan 0%, purple 75%);" , "background-color: green;" ] // call site cycleBackground ( document.body // element to target , backgrounds // list of backgrounds , 3e3 // delay, 3 seconds )
 p { text-align: center; font-size: 3vw; font-weight: bold; color: white; }
 <p>Wait 3 seconds...</p>

The code is fine.代码没问题。 It destroys all the variables because when you call it first time.它会破坏所有变量,因为当您第一次调用它时。 It setTimeout() for the next function and at last return.它为下一个function设置了setTimeout()并最后返回。 You function doesnot return the the next.你的函数不会return下一个。

my_recursion();

function my_recursion () {
 // cycle the Background image ...
 setTimeout(my_recursion, 3000); //Sets timeout for next function.
 //returns undefined here
} 

Adding to https://stackoverflow.com/a/54443904/11022136 .添加到https://stackoverflow.com/a/54443904/11022136 Wanted to give some evidence.想提供一些证据。 Ran the following on node 14.在节点 14 上运行以下命令。

test.js:测试.js:

let i = 10;
const canThisOverflow = () => {
    i--;
    console.trace();
    if (i > 0) setTimeout(canThisOverflow, 1);
}
canThisOverflow();

Output: Stack size does not increase输出:堆栈大小不增加

Trace
    at canThisOverflow (/Users/arjunmalik/Shipsy/query-builder/test.js:4:10)
    at Object.<anonymous> (/Users/arjunmalik/Shipsy/query-builder/test.js:7:1)
    at Module._compile (internal/modules/cjs/loader.js:1063:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
    at Module.load (internal/modules/cjs/loader.js:928:32)
    at Function.Module._load (internal/modules/cjs/loader.js:769:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)
    at internal/main/run_main_module.js:17:47
Trace
    at Timeout.canThisOverflow [as _onTimeout] (/Users/arjunmalik/Shipsy/query-builder/test.js:4:10)
    at listOnTimeout (internal/timers.js:554:17)
    at processTimers (internal/timers.js:497:7)
Trace
    at Timeout.canThisOverflow [as _onTimeout] (/Users/arjunmalik/Shipsy/query-builder/test.js:4:10)
    at listOnTimeout (internal/timers.js:554:17)
    at processTimers (internal/timers.js:497:7)

test2.js:测试2.js:

let i = 10;
const canThisOverflow = () => {
    i--;
    console.trace();
    if (i > 0) canThisOverflow();
}
canThisOverflow();

Output: Stack size increases输出:堆栈大小增加

Trace
    at canThisOverflow (/Users/arjunmalik/Shipsy/query-builder/test2.js:4:10)
    at Object.<anonymous> (/Users/arjunmalik/Shipsy/query-builder/test2.js:7:1)
    at Module._compile (internal/modules/cjs/loader.js:1063:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
    at Module.load (internal/modules/cjs/loader.js:928:32)
    at Function.Module._load (internal/modules/cjs/loader.js:769:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)
    at internal/main/run_main_module.js:17:47
Trace
    at canThisOverflow (/Users/arjunmalik/Shipsy/query-builder/test2.js:4:10)
    at canThisOverflow (/Users/arjunmalik/Shipsy/query-builder/test2.js:5:13)
    at Object.<anonymous> (/Users/arjunmalik/Shipsy/query-builder/test2.js:7:1)
    at Module._compile (internal/modules/cjs/loader.js:1063:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
    at Module.load (internal/modules/cjs/loader.js:928:32)
    at Function.Module._load (internal/modules/cjs/loader.js:769:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)
    at internal/main/run_main_module.js:17:47
Trace
    at canThisOverflow (/Users/arjunmalik/Shipsy/query-builder/test2.js:4:10)
    at canThisOverflow (/Users/arjunmalik/Shipsy/query-builder/test2.js:5:13)
    at canThisOverflow (/Users/arjunmalik/Shipsy/query-builder/test2.js:5:13)
    at Object.<anonymous> (/Users/arjunmalik/Shipsy/query-builder/test2.js:7:1)
    at Module._compile (internal/modules/cjs/loader.js:1063:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
    at Module.load (internal/modules/cjs/loader.js:928:32)
    at Function.Module._load (internal/modules/cjs/loader.js:769:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)
    at internal/main/run_main_module.js:17:47

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM