gpt4 book ai didi

javascript - 在不超过堆栈限制的情况下迭代或递归大量庞大函数的最佳方法是什么?

转载 作者:数据小太阳 更新时间:2023-10-29 04:42:55 26 4
gpt4 key购买 nike

我有一个用 Node.js 编写的应用程序,它需要进行大量配置和数据库调用才能处理用户数据。我遇到的问题是,在 11,800 多次函数调用之后,Node 将抛出错误并退出进程。

错误提示:RangeError:超出最大调用堆栈大小

我很好奇是否有其他人遇到过这种情况,想知道他们是如何处理的。我已经开始将我的代码分解成几个额外的工作文件,但即便如此,每次我处理一个数据 Node 时,它都需要接触 2 个数据库(最多 25 次调用来更新各种表)并进行一些清理检查.

如果是这种情况,我完全愿意承认我可能正在做一些非最佳的事情,但如果有更优化的方式,我会很感激一些指导。

这是我在数据上运行的代码示例:

app.post('/initspeaker', function(req, res) {
// if the Admin ID is not present ignore
if(req.body.xyzid!=config.adminid) {
res.send( {} );
return;
}

var gcnt = 0, dbsize = 0, goutput = [], goutputdata = [], xyzuserdataCallers = [];

xyz.loadbatchfile( xyz.getbatchurl("speakers", "csv"), function(data) {
var parsed = csv.parse(data);
console.log("lexicon", parsed[0]);

for(var i=1;i<parsed.length;i++) {
if(typeof parsed[i][0] != 'undefined' && parsed[i][0]!='name') {
var xyzevent = require('./lib/model/xyz_speaker').create(parsed[i], parsed[0]);
xyzevent.isPresenter = true;
goutput.push(xyzevent);
}
}
dbsize = goutput.length;

xyzuserdataCallers = [new xyzuserdata(),
new xyzuserdata(),
new xyzuserdata(),
new xyzuserdata(),
new xyzuserdata(),
new xyzuserdata(),
new xyzuserdata(),
new xyzuserdata()
];
// insert all Scheduled Items into the DB
xyzuserdataCallers[0].sendSpeakerData(goutput[0]);
for(var i=1;i<xyzuserdataCallers;i++) {
xyzuserdataCallers[i].sendSpeakerData(8008);
}

//sendSpeakerData(goutput[0]);
});

var callback = function(data, func) {
//console.log(data);
if(data && data!=8008) {
if(gcnt>=dbsize) {
res.send("done");
} else {
gcnt++;
func.sendSpeakerData(goutput[gcnt]);
}
} else {
gcnt++;
func.sendSpeakerData(goutput[gcnt]);
}
};

// callback loop for fetching registrants for events from SMW
var xyzuserdata = function() {};
xyzuserdata.prototype.sendSpeakerData = function(data) {
var thisfunc = this;

if(data && data!=8008) {
//console.log('creating user from data', gcnt, dbsize);
var userdata = require('./lib/model/user').create(data.toObject());
var speakerdata = userdata.toObject();
speakerdata.uid = uuid.v1();
speakerdata.isPresenter = true;

couchdb.insert(speakerdata, config.couch.db.user, function($data) {
if($data==false) {
// if this fails it is probably due to a UID colliding
console.log("*** trying user data again ***");
speakerdata.uid = uuid.v1();
arguments.callee( speakerdata );
} else {
callback($data, thisfunc);
}
});
} else {
gcnt++;
arguments.callee(goutput[gcnt]);
}
};

});

这里定义了一些需要介绍的类和项目:

  • 我正在使用 Express.js + 托管 CouchDB,这是对 POST 请求的响应
  • 有一个 CSV 解析器类可以加载驱动提取说话者数据的事件列表
  • 每个事件可以有 n 个用户(目前所有事件大约有 8000 个用户)
  • 我使用的模式是在尝试解析任何数据/用户之前加载所有数据/用户
  • 每个加载的用户(外部数据源)都被转换成一个我可以使用的对象,并且还经过清理(去除斜杠等)
  • 然后将每个用户插入 CouchDB

此代码在应用程序中有效,但过了一会儿我收到一条错误消息,指出已进行了超过 11,800 多次调用并且应用程序中断了。这不是一个包含堆栈跟踪的错误,就像人们会看到它是否是代码错误一样,它由于完成的调用次数而退出。

同样,我们将不胜感激任何帮助/评论/指导。

最佳答案

看起来正在递归使用 xyzuserdata.sendSpeakerData 和回调,以保持数据库调用顺序。在某些时候你用完了调用堆栈......

有几个模块可以使串行执行更容易,比如 StepFlow-JS .

Flow-JS 甚至有一个方便的函数,可以在数组元素上连续应用一个函数:

flow.serialForEach(goutput, xyzuserdata.sendSpeakerData, ...)

我使用 flow.serialForEach 编写了一个小测试程序,但不幸的是能够得到一个 Maximum call stack size exceeded 错误——看起来 Flow-JS 正在以类似的方式使用调用堆栈保持同步。

另一种不建立调用堆栈的方法是避免递归并使用超时值为 0 的 setTimeout 来安排回调调用。看 http://metaduck.com/post/2675027550/asynchronous-iteration-patterns-in-node-js

您可以尝试将回调调用替换为

setTimeout(callback, 0, [$data, thisfunc])

关于javascript - 在不超过堆栈限制的情况下迭代或递归大量庞大函数的最佳方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9100353/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com