使用nedb数据库无递归却报Maximum call stack size exceeded错误如何解决
问题根因
这个RangeError不是你写了显式递归逻辑,是nedb内置的深拷贝函数在序列化待插入数据时,遇到了带循环引用的对象,触发了无限递归导致爆栈。nedb在插入数据前会对数据做深拷贝,碰到a.b = a这类互相引用的结构时,递归就不会停止,直接触发栈溢出。
排查步骤
- 先校验待插入对象是否存在循环引用:在调用
db.insert(updateData)前添加一行测试代码console.log(JSON.stringify(updateData)),如果这一步直接抛出Converting circular structure to JSON的错误,即可确认是待插入数据的问题。 - 逐个检查
updateData的字段值:重点排查key和args[0]两个变量,你是不是直接把Discord.js返回的Message、User、Guild这类框架内置对象直接赋值给了这两个变量?这类对象本身内部存在大量循环引用(比如message.author.message会指回原message对象),直接存入数据库就会触发报错。 - 检查未展示的
findInList函数逻辑:确认该函数是否存在和findPlayer互相调用的逻辑,比如findInList回调里触发findPlayer,findPlayer回调里又触发findInList,满足触发条件的情况下就会形成隐式的回调递归。 - 对比你能正常入库的命令的插入逻辑,看两个场景下插入的字段值有什么差异,重点看是不是正常入库的代码里只存了字符串、数字这类基础类型,而出错的代码里存了对象。
修复方案
- 所有存入nedb的字段都只保留基础类型,不要直接存储框架返回的实例对象:比如要存用户ID就取
message.author.id(字符串类型),要存用户名就取message.author.username,不要把整个message.author对象直接赋值给key。 - 手动提取需要存储的属性,避免未知属性被加入插入对象,示例如下:
// 修正后的赋值逻辑 let updateData = { name: key.toString(), // 确保key是纯字符串 display: args[0].trim(), // 确保args[0]是纯文本 socialCredit: 0, games: [] }
- 调整回调执行顺序,避免隐式递归:可以把
findInList的逻辑放到db.insert的成功回调里执行,确保插入完成后再更新列表,避免异步逻辑互相触发:
db.insert(updateData,function(err,newDoc){ if(err) return console.log(err) message.reply("Added you to the database.") // 插入成功后再操作列表 findInList(key, function(users){ if(!users[0]) { db.update({name:'list'},{$push:{list:key}},{},function(){}); } }) });
内容的提问来源于stack exchange,提问作者Atil
相关产品推荐
相关产品推荐

