当前位置: 首页 > 知识库问答 >
问题:

Map.for创造的promise每个人都在第一次处理拒绝时停下来

宰父衡
2023-03-14

我正在尝试使用节点在Discord上创建一个机器人。js模块不一致。js,在它的一个命令中,它遍历公会(服务器)中的成员地图,并将所有成员都禁用。以下是我使用的代码:

const Discord = require('discord.js');

const client = new Discord.Client();

const map = new Map();

client.once('ready', () => {
    // This is just for demonstration purposes. In the actual code, the values are all different
    // members and the keys are their respective IDs. This is inside the "ready" event because
    // otherwise the client's cache would be empty.
    const hjtunfgb = client.guilds.cache.get('myServerID').members.cache.get('myID');
    map.set(0, hjtunfgb);
    map.set(1, hjtunfgb);
    map.set(2, hjtunfgb);
    map.set(3, hjtunfgb);
    map.set(4, hjtunfgb);
    map.set(5, hjtunfgb);
    map.set(6, hjtunfgb);
    map.set(7, hjtunfgb);
    map.set(8, hjtunfgb);
    map.set(9, hjtunfgb);

    console.log(`Logged in as ${client.user.tag}!`);
});

client.on('message', message => {
    // Here I have two commands: "foo", which mutes everyone in the Map, and "bar", which does other
    // stuff that is not relevant to the problem
    if (message.content.toLowerCase() === 'foo') {
        map.forEach((member, n) => {
            // member.voice.setMute(true) is how the bot mutes people. It returns a promise, that
            // rejects if the member is not connected to any voice channel in that server.
            member.voice.setMute(true)
                .then(() => console.log(n + ' muted!'))
                .catch(() => console.error(n + ' error!'));
        });
    } else if (message.content.toLowerCase() === 'bar') {
        console.log('baz');
    }
});

client.login('myBotsSecretLoginKey');

但是,如果一个成员没有连接到任何语音通道,setMute()方法创建的promise将被拒绝,并且在这里通过记录错误消息来处理它(同样,在实际代码中,拒绝被正确处理)。问题是,在拒绝之后,forEach会停止并不会执行,直到我再次执行“foo”,然后它才会执行。例如,如果我在聊天中发送“foo”,并在“4静音”后立即断开连接如果已记录,则输出如下所示:

0 muted!
1 muted!
2 muted!
3 muted!
4 muted!
5 error!

如果我连接或断开与语音频道的连接,则不会发生任何事情,如果我写入“bar”,则程序正常输出“baz”。然后,如果我加入一个语音频道并再次发送“foo”,则输出以下内容:

0 muted!
6 muted!
7 muted!
8 muted!
9 muted!
1 muted!
2 muted!
3 muted!
4 muted!
5 muted!
6 muted!
7 muted!
8 muted!
9 muted!

因此,在Map上调用了第一个foreach命令,这触发了之前的foreach恢复操作。相反,如果我调用foo,然后加入并第三次调用foo,则前一次调用0错误!输出,后者的输出是

0 muted!
6 muted!
...
9 muted!
1 muted!
...
9 muted!
1 muted!
...
9 muted!

因此,即使拒绝得到处理,forEach也会停止拒绝promise。但是我需要forEach立即恢复,因为bot将不断地静音和取消静音,并且一个断开连接的成员不能阻止其他成员静音。我怎样才能解决这个问题?

编辑:使回调异步并在尝试中包装setMute。。。抓块并没有解决问题。而且,正如有人指出的,forEach确实在任何promise被拒绝之前运行到完成阶段——我通过控制台检查了这一点。运行前记录日志。setMute()。所以,问题在于node discord如何处理promise。js,或不和谐本身。有人能提供信息说明为什么会发生这种情况,以及如何避免这种情况?

我还试着用。。。使用数组而不是映射,但它们都产生了相同的问题。

编辑2:我可以通过更改“message”事件侦听器中的回调来解决此问题,如下所示:

client.on('message', async message => {
    if (message.content.toLowerCase() === 'foo') {
        for (const [n, member] of map) {
            try {
                await member.voice.setMute(true);
                console.log(n + ' muted!');
            } catch (error) {
                console.error(n + ' error!');
            }
        }
    } else if (message.content.toLowerCase() === 'bar') {
        console.log('baz');
    }
});

这样,代码在创建下一个promise之前会等待该promise得到解决。这并不是最理想的方式,因为这些promise可以并行运行,但不一致性会一次处理一个promise,因此在实践中不会影响性能。我尝试使用以下设置在不使用forEach的情况下并行运行promise:

client.on('message', message => {
    if (message.content.toLowerCase() === 'foo') {
        Promise.all(Array.from(map.entries()).map(async ([n, member]) => {
            try {
                await member.voice.setMute(true);
                console.log(n + ' muted!');
            } catch (error) {
                console.error(n + ' error!');
            }
        }));
    } else if (message.content.toLowerCase() === 'bar') {
        console.log('baz');
    }
});

但它也有同样的问题。问题似乎在于节点如何,不协调。js和/或Discord同时处理多个请求的promise。我能做些什么来解决这个问题?同步运行异步代码目前还可以,但从长远来看,并行运行它们会更好。我是否应该将此报告为discord的bug。js和/或Discord,或者有一个我不知道的目的(和修复)?

共有2个答案

毛镜
2023-03-14

在没有看到整个过程的情况下,我无法肯定地告诉您出了什么问题,但人们强烈怀疑setMute有时不会拒绝,而是抛出异常。在这种情况下,forEach将被终止。同样:您可以使用catch处理promise拒绝,但如果发生异常,则不处理在setMute中引发异常(通常,返回promise的函数不应编码为引发异常)。

现在,如果您将forEach内部的函数更改为async,那么您可以在代码内部使用wait,更重要的是,使用try/catch捕获promise拒绝和抛出setMute,如下所示:

client.on("message", (message) => {
    if (message.content.toLowerCase() === "foo") {
        map.forEach(async (member, n) => {
            try {
                await member.voice.setMute(true);
                console.log(n + " muted!");
            } catch (err) {
                console.error(n + " error! " + err);
            }
        });
    } else if (message.content.toLowerCase() === "bar") {
        console.log("baz");
    }
});
宋鸿云
2023-03-14

在forEach循环中不能使用promise(wait)。

看看这个问题。

在forEach循环中使用async/await

干杯

 类似资料:
  • 我得到这个错误- (节点:18420)未处理的PromisejectionWarning:TypeError:无法读取未定义的属性“name” (节点:18420)未处理的PromisejectionWarning:未处理的promise拒绝。此错误源于在没有catch块的情况下抛出异步函数的内部,或者拒绝使用未处理的promise。catch()。要在未处理的promise拒绝时终止节点进程,请

  • 本文介绍了单个promise组合器: 但我没有看到的是,一种运行所有promise的方法,但不是在个人promise被拒绝时短路。我如何确保所有的promise都得到履行,但我能处理拒绝和所有promise的解决?

  • 我想在Repl上为我的游戏实现一个基本的排行榜。它,所以我创建了一个节点。js后端。这是我在后端的配置: 但是每当我尝试发布时,我都会得到以下错误: (节点:344)未处理的PromisejectionWarning:TypeError:无法读取null的属性“push” (节点:344)UnhandledPromiseRejtionWarning:未处理的promise拒绝。这个错误要么是由于抛

  • 我有以下验证函数检查用户是否存在: 以下使用Chai的测试应对此进行测试: 错误确实会被抛出,但是mocha在控制台中显示以下内容: 2)显示抛出,如果用户是未定义的(节点: 18587)UnhandledPromiseRejse警告:未处理的promise拒绝(拒绝id: 2):错误:用户不存在 所以我的问题是,我如何重写测试,让它捕捉到promise拒绝?

  • 我正在努力在以下任务中发送多个AJAX调用。API返回有两个参数:和,并返回指定用户的最后10条消息,从指定的偏移量开始。如果偏移量大于用户的消息总数,API将返回空字符串。 我编写了一个函数,返回一个单独的promise,为指定的和获取10条消息。 我需要使用为多个运行并行任务,但是我无法为每个运行并行子任务(每次将

  • 我正在与节点JS中的promise模式作斗争 我在db中寻找用户,然后用用户引用保存新实体,但当用户不在db中时,我应该返回拒绝,但我不确定如何正确地做到这一点。 有什么办法可以做得更好吗? btw:对不起,coffeescript :-[