最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Javascript: settimeout recursion endless stack increase? - Stack Overflow

programmeradmin1浏览0评论

My goal is a slideshow of background images with 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 e.g. cycle 1000 all the other 999 instances of my_recursion are still open / on the stack? 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"?

My goal is a slideshow of background images with 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 e.g. cycle 1000 all the other 999 instances of my_recursion are still open / on the stack? 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"?

Share Improve this question asked Jan 30, 2019 at 15:16 RobertRobert 4621 gold badge6 silver badges17 bronze badges 10
  • 2 There is only one entry of my_recursion on the stack ever. The first execution finishes pletely before the second one is launched. – VLAZ Commented Jan 30, 2019 at 15:17
  • Probably not exactly a dupe, but I've written before about call stack, recursion, and setTimeout (as a mechanism to interact with the queue) before – VLAZ Commented Jan 30, 2019 at 15:18
  • But why? Does that mean a var x = 1 right after my setTimeout would never be executed? – Robert Commented Jan 30, 2019 at 15:20
  • 1 @Robert the calls to setTimeout() return immediately. The system keeps track of the pending timer and calls the callback function when the time es. – Pointy Commented Jan 30, 2019 at 15:20
  • 2 @Robert no, it's not possible. I urge you to have a look at the other question I linked and potentially look into the event queue more. If your function is still running in 3s then nothing else would be running. Only when it finishes, any other scheduled code would run - you won't get two parallel executions. – VLAZ Commented Jan 30, 2019 at 15:33
 |  Show 5 more ments

4 Answers 4

Reset to default 6

This will not result in endless stack increase, because of the way setTimeout works, and imho it is not bad style.

setTimeout does not guarantee that code will run directly after the given timeout. 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.

If a function calls itself at the end (...)

my_recursion doesn't call itself anywhere. It just passes itself as an argument to 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. You function doesnot return the the next.

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./a/54443904/11022136. Wanted to give some evidence. Ran the following on node 14.

test.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._pile (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:

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._pile (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._pile (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._pile (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
发布评论

评论列表(0)

  1. 暂无评论