Liquid Democracy项目While循环死循环,Vote.find未执行求助
解决Liquid Democracy委托投票功能中的死循环与异步回调问题
你的问题一眼就能看出核心症结:同步的while循环把Node.js的事件循环彻底堵死了,导致MongoDB的异步查询回调完全没有执行的机会。
为什么会这样?
Node.js是单线程的事件循环模型——同步代码会霸占线程一直跑,直到执行完毕;而异步IO操作(比如你的Vote.find)的回调会被放到事件队列里,只有当所有同步代码都跑完,事件循环才会去处理队列里的回调。
你现在的while循环里,delegationsLeft初始设为1,然后就开始无限循环:因为Vote.find的回调根本没机会执行,delegationsLeft永远不会被更新成0,循环就停不下来;同时事件队列里的回调被压着,永远进不去Vote.find的回调里,自然看不到"I'm in."的日志。
怎么修复?
我们需要把同步的while循环改成异步的循环方式,用async/await来重构代码——既保留你的逻辑,又不会阻塞事件循环,还能解决原来的回调嵌套和闭包问题。
首先,把MongoDB的回调式API改成Promise版本(mongoose默认支持返回Promise,不用传回调),然后用async/await来写异步逻辑:
async function processDelegations(propId) { try { // 获取委托投票总数 const voteNumber = await Vote.count({ propId: propId, delegation: true }); const maxDelegation = voteNumber; // 遍历每个权重等级 for (let d = 1; d <= maxDelegation; d++) { let delegationsLeft; // 用do-await-while实现异步循环,确保每次先执行查询再判断 do { console.log(`I am about to find the votes for ${d} weight, ${delegationsLeft || 1} delegation left at least.`); // 异步查询当前权重的委托投票 const specWeightVotes = await Vote.find({ propId: propId, delegation: true, weight: d }); console.log("I'm in."); delegationsLeft = specWeightVotes.length; // 逐个处理委托投票 for (const vote of specWeightVotes) { try { // 给被委托者增加权重 await Vote.findOneAndUpdate( { propId: propId, voter: vote.content }, { $inc: { weight: vote.weight } } ); // 将当前委托投票的权重设为0 await Vote.findOneAndUpdate( { _id: vote._id }, { $set: { weight: 0 } } ); } catch (updateErr) { console.error(`处理投票${vote._id}时出错:`, updateErr); } } } while (delegationsLeft > 0); } console.log("I have delegated all votes"); } catch (err) { console.error("处理委托流程时出错:", err); } } // 调用这个函数来处理委托 processDelegations(propId);
重构的关键点说明:
- 用async/await替代回调:把异步操作写成同步风格,既避免了回调地狱,又能让事件循环在await时让出线程,处理其他任务,不会阻塞。
- 异步循环代替同步while:
do-await-while确保每次循环都会先执行异步查询,更新delegationsLeft的值,不会出现死循环。 - 解决闭包问题:用
for...of遍历投票列表,代替原来的for(var i...)——原来的var会导致回调执行时i已经是循环结束的值,出现错误。 - 错误处理:添加了try/catch捕获整个流程和单个更新的错误,方便调试和问题定位。
额外提醒
原来的代码还有个隐藏问题:嵌套的findOneAndUpdate回调里,specWeightVotes[i]的i值在回调执行时已经不是当前循环的i了(因为var的作用域问题),这会导致更新错误的投票记录。用async/await和for...of就能彻底解决这个问题。
内容的提问来源于stack exchange,提问作者Adrien Merlier
相关产品推荐
相关产品推荐

