Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/416.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript Map.forEach创建的承诺在第一次处理拒绝时停止_Javascript_Node.js_Discord.js - Fatal编程技术网

Javascript Map.forEach创建的承诺在第一次处理拒绝时停止

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

我正在尝试使用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 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以自己的速度让所有成员沉默,那么为什么它在这里不起作用呢?