V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
revir
V2EX  ›  JavaScript

请教 setTimeout 为什么不会导致栈溢出?

  •  
  •   revir · 2014-10-20 17:12:28 +08:00 · 5978 次点击
    这是一个创建于 3692 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近在用js处理任务的时候发生了栈溢出问题, 原来是递归调用函数的次数太多, 函数栈没有来得及释放导致, 用 setTimeout 调用递归函数解决了我的问题, 但是还有一些不明之处, 请大家指教!

    1. 下面这个函数明显会导致栈溢出, 用node执行到 17000 多次的时候就报: RangeError: Maximum call stack size exceeded.
    func1 = function(i) {
        i += 1;
        console.log(i);
        if (i > 1000000) {
          return;
        }
        return func1(i);
      };
    
      func1(0);
    
    1. 但是改成用 setTimeout 调用就不会。
    func2 = function(i) {
        i += 1;
        console.log(i);
        if (i > 1000000) {
          return;
        }
        return setTimeout((function() {
          return func2(i);
        }), 0);
      };
    
      func2(0);
    

    我的疑惑就是 setTimeout 中的函数调用时, 之前的函数堆栈有没有被释放呢? 如果有的话变量 i 是怎么传进去的; 如果没有的话, 这段代码为什么不会栈溢出。

    8 条回复    2014-10-21 10:48:59 +08:00
    xieguanglei
        1
    xieguanglei  
       2014-10-20 17:25:38 +08:00   ❤️ 2
    前一个,直到栈溢出,第一次func1函数调用都没有结束。

    后一个
    return setTimeout((function() {
    return func2(i);
    }), 0);
    这一句之后,这一次func2函数就结束了。

    函数堆栈释放,变量i没有释放,具体请Google下 [闭包] 。
    revir
        2
    revir  
    OP
       2014-10-20 17:36:41 +08:00
    @xieguanglei
    嗯, 闭包的概念懂一些, 但是有些糊涂, 后一次堆栈释放了, 变量i没有释放吗? 那这样应该也会造成内存泄漏吧?
    谢谢!
    revir
        3
    revir  
    OP
       2014-10-20 17:41:03 +08:00
    @xieguanglei
    刚刚测试发现内存占用确实会越来越大, gotcha!
    revir
        4
    revir  
    OP
       2014-10-20 17:50:24 +08:00
    神奇的闭包原来是创建在堆上的, 难怪不会栈溢出!
    chemzqm
        5
    chemzqm  
       2014-10-20 18:04:34 +08:00
    我的理解是 setTimeout 实际上把函数丢到下一次轮询的栈队列去了,i是值传递,如果是对象还有可能造成内存泄露
    jakwings
        6
    jakwings  
       2014-10-20 18:41:35 +08:00
    @chemzqm 这和 for 循环操作差不多。

    @revir 问题是 setTimeout 是即时返回一个 Timer ID 的啊,都没有递归。
    revir
        7
    revir  
    OP
       2014-10-21 09:50:57 +08:00
    @chemzqm
    不对, 我试过了, 如果是对象, 也是一样的。

    @jakwings
    嗯,确实没有递归
    chemzqm
        8
    chemzqm  
       2014-10-21 10:48:59 +08:00
    @revir 可能会引用无法释放导致内存泄露,不会栈溢出
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3117 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 14:16 · PVG 22:16 · LAX 06:16 · JFK 09:16
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.