Javascript:settimeout递归无休止地增加堆栈?

时间:2019-01-30 15:16:21

标签: javascript recursion slideshow

我的目标是使用HTML / CSS / JS幻灯片播放背景图片。我发现许多解决方案都可以促进诸如此类的事情:

my_recursion();

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

我错误地认为这是不好的风格吗?我希望在例如循环1000 my_recursion的所有其他999个实例是否仍处于打开状态/在堆栈上?这样会不会创建消耗更多内存的无限堆栈?

还是涉及某种智能,例如“如果一个函数在最后调用自身,第(n-1)个函数将被破坏,包括在其中分配的所有变量”?

4 个答案:

答案 0 :(得分:3)

由于setTimeout的工作方式,这不会导致堆栈不断增加,而且恕我直言,这还不错。

setTimeout不保证代码将在给定的超时后直接运行。取而代之的是,在超时之后,它将把回调推送到“队列”上,当堆栈为空时将对其进行处理。因此,它将仅在my_recursion返回并且堆栈为空时运行。

  

如果函数在最后调用自己(...)

my_recursion不会在任何地方调用自己。它只是将自身作为参数传递给setTimeout。之后,它将继续执行,之后立即返回,并将其从堆栈中弹出。

This presentation explains the stack and the event queue.

答案 1 :(得分:1)

在您的问题中,您的函数没有任何参数。在一个实际的实现中,希望您打算使用它们。

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>

答案 2 :(得分:0)

代码很好。它会破坏所有变量,因为在您第一次调用它时。 setTimeout()用于下一个function,最后返回。下一个功能不会return

my_recursion();

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

答案 3 :(得分:0)

添加到 https://stackoverflow.com/a/54443904/11022136。 想提供一些证据。 在节点 14 上运行以下命令。

test.js:

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

输出:堆栈大小不增加

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:

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

输出:堆栈大小增加

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