You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

for循环中使用setTimeout更新MongoDB数据时,Bee角色能量耗尽后无法恢复状态的问题修复咨询

问题分析与修复方案

你遇到的问题主要来自两个核心点:循环中的闭包变量陷阱和数据库更新未持久化,咱们一步步拆解解决:

1. 循环闭包导致的变量引用错误

你的for循环里,变量a是在循环外部作用域声明的。当5秒后setTimeout的回调执行时,循环早就跑完了,a的值会变成en.length + 1,这时候data.Hives[Hive${a}]根本不存在,自然没法修改属性。

解决这个问题最直观的方式是改用forEach遍历,每个回调函数都有独立的作用域,能正确捕获当前的 hive 键值。

2. 数据库未持久化更新

你在setTimeout里只修改了内存中的data对象,但没有把这些修改保存到数据库。而且原来的Hive.findOneAndUpdate(user, data)是在循环结束后立刻执行的,这时候setTimeout的回调还没触发,后续的属性恢复操作完全不会被持久化。

正确的做法是在setTimeout回调里,重新查询最新的数据库数据,修改后再调用save()完成持久化。

修复后的完整代码

// 上方无关代码
Hive.findOne({ User: message.author.id }, async (err, data) => {
    // 此处无关代码
    const arr = [];
    // 改用forEach遍历,规避闭包变量问题
    Object.keys(data.Hives).forEach(async (key) => {
        const hive = data.Hives[key];
        if (!isNaN(hive.Energy)) {
            hive.Energy -= 1;
            if (hive.Energy < 1) {
                arr.push(`😴 Your ${hive.Bee} is out of energy! It's going to sleep.`);
                hive.Gathers = 0;
                hive.Converts = 0;
                
                setTimeout(async () => {
                    // 重新查询数据库,确保拿到最新数据
                    const latestHiveData = await Hive.findOne({ User: message.author.id });
                    if (!latestHiveData) return;
                    
                    const targetHive = latestHiveData.Hives[key];
                    if (!targetHive) return;
                    
                    // 恢复Bee的所有属性
                    targetHive.Energy = targetHive.MaxEnergy;
                    targetHive.Gathers = 2.5 * (1 + 0.1 * (targetHive.Level - 1));
                    targetHive.Converts = (80 * (1 + 0.1 * (2 - 1)) * statsProfile.ConvertRate) / 100;
                    
                    // 将修改持久化到数据库
                    await latestHiveData.save();
                }, 5000);
            }
        }
    });
    
    if (arr.length !== 0) {
        message.reply({
            embeds: [
                new Discord.MessageEmbed()
                .setTitle("Out of energy...")
                .setDescription(arr.join(`\n`))
                .setColor("ffbe42"),
            ],
        });
    }
    
    // 先保存当前的能量扣除等修改
    await data.save();
});

关键修改说明

  • forEach遍历替代for循环:每个回调拥有独立作用域,确保setTimeout能正确引用到对应的 hive 数据。
  • setTimeout内重新查询数据:避免因其他并发操作导致的脏数据问题,保证修改的是最新的数据库记录。
  • 在回调内调用save():把属性恢复的操作真正写入数据库,而不是只修改内存中的临时对象。
  • 提前保存当前修改:循环中的能量扣除等操作,需要先持久化到数据库,避免丢失。

这样修改后,当Bee能量归0时,5秒后就能正确恢复所有属性了。

内容的提问来源于stack exchange,提问作者PG3DGAMING

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 14:17:41