Node.js - 超出最大调用堆栈大小 [英] Node.js - Maximum call stack size exceeded

查看:65
本文介绍了Node.js - 超出最大调用堆栈大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我运行我的代码时,Node.js 会抛出一个 RangeError: Maximum call stack size exceeded" 异常,原因是递归调用过多.我试图通过 sudo node --stack-size=16000 app 增加 Node.js 堆栈大小,但 Node.js 崩溃没有任何错误消息.当我在没有 sudo 的情况下再次运行它时,Node.js 会打印 'Segmentation fault: 11'.有没有可能在不删除我的递归调用的情况下解决这个问题?

When I run my code, Node.js throws a "RangeError: Maximum call stack size exceeded" exception caused by too many recursive calls. I tried to increase Node.js stack size by sudo node --stack-size=16000 app, but Node.js crashes without any error message. When I run this again without sudo, then Node.js prints 'Segmentation fault: 11'. Is there a possibility to solve this without removing my recursive calls?

推荐答案

你应该把你的递归函数调用包装成一个

You should wrap your recursive function call into a

  • setTimeout,
  • setImmediate
  • process.nextTick

函数让 node.js 有机会清除堆栈.如果你不这样做并且有很多循环没有任何真正的异步函数调用,或者如果你不等待回调,你的RangeError: Maximum call stack size exceeded不可避免.

function to give node.js the chance to clear the stack. If you don't do that and there are many loops without any real async function call or if you do not wait for the callback, your RangeError: Maximum call stack size exceeded will be inevitable.

关于潜在异步循环"的文章很多.这是一个.

There are many articles concerning "Potential Async Loop". Here is one.

现在还有一些示例代码:

Now some more example code:

// ANTI-PATTERN
// THIS WILL CRASH

var condition = false, // potential means "maybe never"
    max = 1000000;

function potAsyncLoop( i, resume ) {
    if( i < max ) {
        if( condition ) { 
            someAsyncFunc( function( err, result ) { 
                potAsyncLoop( i+1, callback );
            });
        } else {
            // this will crash after some rounds with
            // "stack exceed", because control is never given back
            // to the browser 
            // -> no GC and browser "dead" ... "VERY BAD"
            potAsyncLoop( i+1, resume ); 
        }
    } else {
        resume();
    }
}
potAsyncLoop( 0, function() {
    // code after the loop
    ...
});

这是对的:

var condition = false, // potential means "maybe never"
    max = 1000000;

function potAsyncLoop( i, resume ) {
    if( i < max ) {
        if( condition ) { 
            someAsyncFunc( function( err, result ) { 
                potAsyncLoop( i+1, callback );
            });
        } else {
            // Now the browser gets the chance to clear the stack
            // after every round by getting the control back.
            // Afterwards the loop continues
            setTimeout( function() {
                potAsyncLoop( i+1, resume ); 
            }, 0 );
        }
    } else {
        resume();
    }
}
potAsyncLoop( 0, function() {
    // code after the loop
    ...
});

现在您的循环可能会变得太慢,因为我们每轮都会浪费一点时间(一次浏览器往返).但是您不必在每一轮中都调用 setTimeout.通常是可以的.每 1000 次执行一次.但这可能会因您的堆栈大小而异:

Now your loop may become too slow, because we loose a little time (one browser roundtrip) per round. But you do not have to call setTimeout in every round. Normally it is o.k. to do it every 1000th time. But this may differ depending on your stack size:

var condition = false, // potential means "maybe never"
    max = 1000000;

function potAsyncLoop( i, resume ) {
    if( i < max ) {
        if( condition ) { 
            someAsyncFunc( function( err, result ) { 
                potAsyncLoop( i+1, callback );
            });
        } else {
            if( i % 1000 === 0 ) {
                setTimeout( function() {
                    potAsyncLoop( i+1, resume ); 
                }, 0 );
            } else {
                potAsyncLoop( i+1, resume ); 
            }
        }
    } else {
        resume();
    }
}
potAsyncLoop( 0, function() {
    // code after the loop
    ...
});

这篇关于Node.js - 超出最大调用堆栈大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆