Javascript Map.forEach创建的承诺在第一次处理拒绝时停止
我正在尝试使用Node.js模块Discord.js在Discord上创建一个bot,在它的一个命令中,它遍历公会(服务器)中的成员地图,并将所有成员禁用。以下是我使用的代码:Javascript Map.forEach创建的承诺在第一次处理拒绝时停止,javascript,node.js,discord.js,Javascript,Node.js,Discord.js,我正在尝试使用Node.js模块Discord.js在Discord上创建一个bot,在它的一个命令中,它遍历公会(服务器)中的成员地图,并将所有成员禁用。以下是我使用的代码: const Discord = require('discord.js'); const client = new Discord.Client(); const map = new Map(); client.once('ready', () => { // This is just for dem
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()方法创建的承诺将被拒绝,并且在这里通过记录错误消息来处理它(同样,在实际代码中,拒绝被正确处理)。问题是,在拒绝之后,forEach会停止并不会执行,直到我再次执行“foo”,然后它才会执行。例如,如果我在聊天中发送“foo”,并在记录“4muted!”后立即断开连接,则输出如下所示:
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!
因此,在映射上调用第一个forEach命令,这将触发前一个forEach以恢复操作。相反,如果我调用“foo”,然后加入并第三次调用“foo”,则前一次调用0错误代码>输出,在后者上输出
0 muted!
6 muted!
...
9 muted!
1 muted!
...
9 muted!
1 muted!
...
9 muted!
因此,即使拒绝得到处理,forEach也会停止拒绝承诺。但是我需要forEach立即恢复,因为bot将不断地静音和取消静音,并且一个断开连接的成员不能阻止其他成员静音。我怎样才能解决这个问题
编辑:使回调异步并在try…catch块中包装setMute并不能解决问题。而且,正如有人指出的,forEach确实在任何承诺被拒绝之前一直运行到完成——我通过console.logging before running.setMute()检查了这一点。因此,问题在于node、discord.js或discord本身如何处理承诺。有人能提供信息说明为什么会发生这种情况,以及如何避免这种情况
我还尝试使用for…of和使用数组而不是贴图,但它们都产生了相同的问题
编辑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');
}
});
这样,代码在创建下一个承诺之前会等待该承诺得到解决。这并不是最理想的方式,因为这些承诺可以并行运行,但不一致性会一次处理一个承诺,因此在实践中不会影响性能。我尝试使用以下设置在不使用forEach的情况下并行运行承诺:
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');
}
});
但它也有同样的问题。问题似乎在于node、discord.js和/或discord如何处理同时请求的多个承诺。我能做些什么来解决这个问题?同步运行异步代码目前还可以,但从长远来看,并行运行它们会更好。我应该将此作为bug报告给discord.js和/或discord,还是有一个我不知道的目的(和修复方法)?在没有看到全部情况的情况下,我无法肯定地告诉您出了什么问题,但有一种强烈的怀疑是,setMute
有时不会拒绝,但会抛出异常。在这种情况下,forEach将被终止。同样:您可以使用catch
处理承诺拒绝,但如果发生异常,则不处理在setMute
中引发异常(通常,返回承诺的函数不应编码为引发异常)
现在,如果您将forEach内部的函数更改为async
,那么您可以在代码内部使用wait
,更重要的是,使用try/catch
捕获承诺拒绝和抛出setMute
,如下所示:
client.on(“message”,(message)=>{
if(message.content.toLowerCase()=“foo”){
map.forEach(异步(成员,n)=>{
试一试{
wait member.voice.setMute(true);
log(n+“静音!”);
}捕捉(错误){
console.error(n+“error!”+err);
}
});
}else if(message.content.toLowerCase()=“bar”){
控制台日志(“baz”);
}
});
您不能在forEach循环中使用promise(wait)
看看这个问题
干杯。forEach在拒绝承诺时暂停
听起来难以置信,因为任何拒绝都不会在forEach遍历整个地图之前发生-如果你console.log(n+“静音”)
在member.voice.setMute之前你会看到我所说的mean@JaromandaX的确你说得对!它可能与Discord、Discord.js或节点本身有关。。。我要编辑它来指出这一点!感谢您的编辑,@jakye-您的编辑完全有意义该代码段不可执行,因此我将其删除。如果它引发异常,程序将崩溃,并且肯定会发送错误消息。尽管如此,我还是尝试了它,但没有任何改变……正如在前面提到的文章中所写的那样,它只是触发了多个异步调用,但printFiles函数会立即返回。然而,我不想要承诺的解决价值,我只想请求Discord以自己的速度让所有成员沉默,那么为什么它在这里不起作用呢?