无限定时器的循环使用JavaScript(无setInterval的)?(Infinite Time

2019-07-04 01:17发布

有人问我(一个朋友)建立一个定时器(无限其中之一写入一行每秒),但没有setInterval

我解决它:

var i = 0;

    function k(myId, cb)
    {
        setTimeout(function ()
        {
            console.log(myId);
            cb();
        }, 1000);
    }

    function go()
    {
        i++;
        k(i, go);
    }

    go();

而且这是工作。

问题是,恐怕会是一个内存压力。 实际上,它创建了一个递归和(周或某事),经过一段时间 - 的过程中会消耗大量的内存。 (堆被永远不会释放)

我怎样才能改变我的代码,以便没有多大的内存消耗?

Answer 1:

这不是递归

它可能看起来像递归,但setTimeout的不创建递归。

setTimeout的工作方式是,它立即返回。 所以调用k结束立即用它的堆栈释放。

当超时实际发生,并调用go再次发生它是不是从以前调用点k但是从全球范围内*。

*注:我没有使用在规范的ECMAScript这里定义的范围严格意义。 我的意思是将呼叫k将被搞得好像你在一个普通的写它<script></script>标签:也就是说,任何其他函数调用之外。

对于在关闭您的关注

在特定情况下,有这其实包含在被创建的闭包很少k功能。 唯一显著闭包是参考参数cbmyId 。 而且即便如此,它仅持续约一秒钟:

 #1   function k(myId, cb) {
 #2        setTimeout(function(){
 #3            console.log(myId); // there is a closure here to myId
 #4            cb();              // and another one for cb
 #5
             /* But at this point in the function, setTimeout ends
             * and as the function returns, there are no remaining
             * references to either "cb" or "myId" accessible
             * anywhere else. Which means that the GC can immediately
             * free them (though in reality the GC may run a bit later)
             */
  #6       }, 1000); // So one second is roughly the longest the closure lasts
    }

比这更简单

我要指出,你的代码是相当令人费解。 它可以写简单,且无需在所有使用闭包(减去全局变量i)如果你只是把它写这样的:

// Simpler, does exactly the same thing:
var i = 0;
function go () {
    console.log(i);
    i++;
    setTimeout(go, 1000); // callback
}
go();


Answer 2:

这条线是假的:

实际上,它创建了一个递归和(周或某事),经过一段时间 - 的过程中会消耗大量的内存。 (堆被永远不会释放)

不会产生递归,因为该功能完全退出,然后再调用。

递归堆叠在彼此的顶部

function a() {a()}; // function calls itself until a stack overflow.

堆栈看起来是这样的

a()
  a()
    a()
      a() ... until a crash.

随着setTimeout的,你执行一个功能。 这个函数设置功能再次运行一个事件 - 但这里是重要的区别:函数退出,完整,没有了[1]。 然后,它再次调用。

执行明智的,它是不是从这样做太大的不同:

function a() {console.log("I am called");}

a(); // Call the function;
a(); // Call the function again
a(); // Call the function again

setTimeout只是给浏览器有机会“呼吸”如果你愿意。 用于屏幕更新的机会,其他事件来处理。 它不,使用正确的术语, block浏览器。



Answer 3:

这不会产生内存泄漏。

事实上,这是一个非常常用的概念。 通常它会出现在这种形式:

setTimeout(function next() {

    // Do something...

    // Have the function set another timeout to call itself later.
    setTimeout(next, 10);

}, 10);

当您要检查的东西往往(这里每10毫秒),它可以更好地使用这种模式,而不是setInterval ,因为它可以提高你的页面的性能。 举例来说,如果你的函数需要超过10毫秒来执行,并且您使用setInterval(f, 10)那么它将被不断地被调用。 但是,如果您使用setTimeout上面的图案,这将至少确保处理器得到每个调用之间的10毫秒的突破,无论你的功能需要多长时间来执行。

见保罗爱尔兰这个视频(始于7:46)关于该模式的更多信息。



文章来源: Infinite Timer Loop with javascript ( no setInterval)?