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

JavaScript async forEach异步循环未结束就执行后续代码问题

问题根因

执行顺序错乱的核心原因是Array.forEach本身不支持等待异步回调执行:传入forEach的async函数会被直接放到异步事件队列,forEach本身不会等回调执行完就直接往下走同步代码,所以会先执行console.log(2)和后续的删除判断,等所有同步代码执行完才会跑遍历里的异步逻辑、打印console.log(1)。这时候deletedMessagesIds还没完成数据填充,删除逻辑的判断结果自然不对。

修复方案

不要用forEach处理需要等待异步执行完成的遍历场景,替换为支持异步等待的遍历写法即可,两种常用实现可按需选择:

方案1:for...of 串行校验

和原本预期的执行顺序完全一致,会按数组顺序逐个校验消息状态,上一个校验完成才会处理下一个,逻辑直观易调试:

const {
    reactionRoleInformation,
} = require("../database-functions/reactionroles/reactionRoleInformation");
const {
    deleteManyReactionRoles,
} = require("../database-functions/reactionroles/deleteManyReactionRoles");

module.exports.cacheMessages = async (bot) => {
    const messageArray = await reactionRoleInformation();
    const deletedMessagesIds = [];

    // 替换原forEach为for...of循环
    for (const message of messageArray) {
        try {
            await bot.guilds.cache
                .get(message.guild)
                .channels.cache.get(message.channel)
                .messages.fetch(message.id);
            console.log(1);
            // 注:原代码此处重复调用了一次相同的messages.fetch,属于冗余逻辑已移除,有特殊业务需求可自行恢复
        } catch (err) {
            deletedMessagesIds.push(message.uniqueId);
        }
    }

    console.log(2);
    if (deletedMessagesIds.length !== 0) {
        await deleteManyReactionRoles(deletedMessagesIds);
    }
};

方案2:Promise.all 并行校验

如果消息量级不大、不需要严格按顺序校验,可以用并发校验的方式,执行效率比串行高很多:

const {
    reactionRoleInformation,
} = require("../database-functions/reactionroles/reactionRoleInformation");
const {
    deleteManyReactionRoles,
} = require("../database-functions/reactionroles/deleteManyReactionRoles");

module.exports.cacheMessages = async (bot) => {
    const messageArray = await reactionRoleInformation();

    // 并发执行所有校验任务,统一等待所有任务执行完成
    const checkResults = await Promise.all(
        messageArray.map(async (message) => {
            try {
                await bot.guilds.cache
                    .get(message.guild)
                    .channels.cache.get(message.channel)
                    .messages.fetch(message.id);
                console.log(1);
                return null;
            } catch (err) {
                return message.uniqueId;
            }
        })
    );
    // 过滤掉校验通过返回的null,剩余就是需要删除的消息ID
    const deletedMessagesIds = checkResults.filter(id => id !== null);

    console.log(2);
    if (deletedMessagesIds.length !== 0) {
        await deleteManyReactionRoles(deletedMessagesIds);
    }
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 03:48:28