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

推荐答案

您应该将递归函数调用包装成

  • setTimeout,
  • setImmediate
  • process.nextTick

函数来指定 node .js是清除堆栈的机会.如果不这样做,并且有许多循环没有任何real异步函数调用,或者如果不等待回调,那么RangeError: Maximum call stack size exceeded将是inevitable.

有很多关于"潜在异步循环"的文章.Here is one

下面是一些示例代码:

// 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分.通常每setTimeout0次就可以了.但这可能因堆栈大小而异:

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相关问答推荐

使用Moongose处理node.js中重定向的then()块链

Sveltekit停靠的应用程序找不到从Build导入的包

Mongoose-不会更新数组中的属性值

如何在MongoDB中更新嵌套数组

在内存中加载安全密钥安全吗?还是每次都从文件中读取?

如何修复PostgreSQL和NodeJS/NestJS应用程序之间的日期时间和时区问题?

找不到 vue-template-compiler@2.6.14 的匹配版本 | Shopware 6.5 更新后的 node 问题

Promise 和 Azure 语音转文本

在构建完成后,将AddedFiles文件夹的内容复制到dist文件夹

如何使用mongoose引用不在项目中的模型

Gulp 能否向 Docker 发出增量构建的第一次迭代完成的信号?

Typescript :泛型类又扩展了另一个泛型类

Typescript typeRoots 未检测到类型定义

如何找到特定文档并更新数组中特定键的值?

来自 child_process.exec 的错误没有这样的设备或地址,管道有帮助.为什么?

Firestore promise 在退货前等待产品详细信息

为什么 req.params.id 返回 undefined未定义?

Node.js、Cygwin 和 Socket.io 走进一家wine 吧……Node.js 抛出 ENOBUFS,所有人都死了

当进程被杀死时,如何优雅地关闭我的 Express 服务器?

AWS Lambda 函数写入 S3