Discord.js - 尝试等待异步进程并允许递归调用包装器
Discord.js - Trying to both await an async process and allow recursive calls of a wrapper
这个有很多移动部件,我试图尽可能简化,我仍在学习 async/await 处理,所以请耐心等待 -
所以我正在尝试使用 discord.js 为 Discord 聊天机器人编写聊天命令。我遇到问题的命令由 !aut
开头的消息触发,应该接受用户输入的字符串(跟在命令本身之后)和 return 另一个字符串;如果用户不提供字符串,我希望它立即在包含命令的消息上方获取消息的内容(即最近的第二个)并将其用作输入字符串。
但是,在测试后一种情况时,它不断抛出此错误:
(node:17896) UnhandledPromiseRejectionWarning: DiscordAPIError: Cannot send an empty message
我用一个事件侦听器构建了机器人,该侦听器侦听命令并在检测到命令时调用包装函数 execute(string, channel)
;包装器然后为该命令调用适当的实用程序函数以获取一个字符串,然后将其传递回监听器,然后监听器将字符串发送到通道。
效用函数 com_aut(array)
运行良好;问题是包装器中定义的默认空字符串 sComResult
在被 com_aut
:
覆盖之前被 returned 给监听器
client.on('message', pMessage => {
if (executable(pMessage.content) == true) {
let sResult = execute(pMessage.content, pMessage.channel);
pMessage.channel.send(sResult);
}
});
function execute(sMessage, pChannel = null) {
// strip off the initial ! that marks the message as a command; whatever comes immediately afterwards is the command
let args = sMessage.substring(1).trim().split(/ +/g);
let cmd = args[0];
// don't include the command itself among the rest of the arguments passed to it
args = args.splice(1);
let sComResult = "";
switch(cmd){
...
case "aut":
if (args.length < 1) {
// input string that should be in args actually isn't, so grab the content of the 2nd most recent message instead
pChannel.fetchMessages({ limit: 2 }).then(pMessages => {
sComResult = com_aut([pMessages.last().content]);
});
} else {
// input string is present in args, so just use that
sComResult = com_aut(args);
}
break;
}
return sComResult;
}
TextChannel.fetchMessages
是异步的 - 或者 return 至少是一个 Promise - 所以我也尝试让包装器异步,这样我就可以强制它 await
。加上侦听器中的必要更改,我发现这有效:
client.on('message', pMessage => {
if (executable(pMessage.content) == true) {
execute(pMessage.content, pMessage.channel).then(sResult => { pMessage.channel.send(sResult) });
}
});
async function execute(sMessage, pChannel = null) {
// strip off the initial ! that marks the message as a command; whatever comes immediately afterwards is the command
let args = sMessage.substring(1).trim().split(/ +/g);
let cmd = args[0];
// don't include the command itself among the rest of the arguments passed to it
args = args.splice(1);
let sComResult = "";
switch(cmd){
...
case "aut":
if (args.length < 1) {
// input string that should be in args actually isn't, so grab the content of the 2nd most recent message instead
pMessages = await pChannel.fetchMessages({ limit: 2 });
sComResult = com_aut([pMessages.last().content]);
});
} else {
// input string is present in args, so just use that
sComResult = com_aut(args);
}
break;
}
return sComResult;
}
但是,现在的问题是我无法递归调用 execute(string, channel)
,这是我在将一个字符串输出命令的输出通过管道传输到另一个字符串输入命令时所做的。 (这也是包装器首先存在的原因,而不是将侦听器直接链接到实用程序函数的原因)这涉及 execute
本身内的 execute
调用。此时我只是 link to pastebin,但它抛出类型错误,因为它无法从嵌套的 execute
中取回值,因此它最终尝试调用 null.then
:
(node:6796) UnhandledPromiseRejectionWarning: TypeError: pInnerPromise.then is not a function
我如何构造我的代码,以便它在继续之前正确地等待 fetchMessages 查询,但仍然允许递归调用包装函数(或其他一些管道方式)?
您的代码
if (executable(sInnerCom) == true) {
// here you are using await so promise is already resolved.
let pInnerPromise = await execute(sInnerCom, pChannel);
// no need to use then, you can return result direct
pInnerPromise.then(result => { sInnerComResult = result });
}
应该是这样的
if (executable(sInnerCom) == true) {
let result = await execute(sInnerCom, pChannel);
sInnerComResult = result ;
}
或者像这样
if (executable(sInnerCom) == true) {
sInnerComResult = await execute(sInnerCom, pChannel);
}
这个有很多移动部件,我试图尽可能简化,我仍在学习 async/await 处理,所以请耐心等待 -
所以我正在尝试使用 discord.js 为 Discord 聊天机器人编写聊天命令。我遇到问题的命令由 !aut
开头的消息触发,应该接受用户输入的字符串(跟在命令本身之后)和 return 另一个字符串;如果用户不提供字符串,我希望它立即在包含命令的消息上方获取消息的内容(即最近的第二个)并将其用作输入字符串。
但是,在测试后一种情况时,它不断抛出此错误:
(node:17896) UnhandledPromiseRejectionWarning: DiscordAPIError: Cannot send an empty message
我用一个事件侦听器构建了机器人,该侦听器侦听命令并在检测到命令时调用包装函数 execute(string, channel)
;包装器然后为该命令调用适当的实用程序函数以获取一个字符串,然后将其传递回监听器,然后监听器将字符串发送到通道。
效用函数 com_aut(array)
运行良好;问题是包装器中定义的默认空字符串 sComResult
在被 com_aut
:
client.on('message', pMessage => {
if (executable(pMessage.content) == true) {
let sResult = execute(pMessage.content, pMessage.channel);
pMessage.channel.send(sResult);
}
});
function execute(sMessage, pChannel = null) {
// strip off the initial ! that marks the message as a command; whatever comes immediately afterwards is the command
let args = sMessage.substring(1).trim().split(/ +/g);
let cmd = args[0];
// don't include the command itself among the rest of the arguments passed to it
args = args.splice(1);
let sComResult = "";
switch(cmd){
...
case "aut":
if (args.length < 1) {
// input string that should be in args actually isn't, so grab the content of the 2nd most recent message instead
pChannel.fetchMessages({ limit: 2 }).then(pMessages => {
sComResult = com_aut([pMessages.last().content]);
});
} else {
// input string is present in args, so just use that
sComResult = com_aut(args);
}
break;
}
return sComResult;
}
TextChannel.fetchMessages
是异步的 - 或者 return 至少是一个 Promise - 所以我也尝试让包装器异步,这样我就可以强制它 await
。加上侦听器中的必要更改,我发现这有效:
client.on('message', pMessage => {
if (executable(pMessage.content) == true) {
execute(pMessage.content, pMessage.channel).then(sResult => { pMessage.channel.send(sResult) });
}
});
async function execute(sMessage, pChannel = null) {
// strip off the initial ! that marks the message as a command; whatever comes immediately afterwards is the command
let args = sMessage.substring(1).trim().split(/ +/g);
let cmd = args[0];
// don't include the command itself among the rest of the arguments passed to it
args = args.splice(1);
let sComResult = "";
switch(cmd){
...
case "aut":
if (args.length < 1) {
// input string that should be in args actually isn't, so grab the content of the 2nd most recent message instead
pMessages = await pChannel.fetchMessages({ limit: 2 });
sComResult = com_aut([pMessages.last().content]);
});
} else {
// input string is present in args, so just use that
sComResult = com_aut(args);
}
break;
}
return sComResult;
}
但是,现在的问题是我无法递归调用 execute(string, channel)
,这是我在将一个字符串输出命令的输出通过管道传输到另一个字符串输入命令时所做的。 (这也是包装器首先存在的原因,而不是将侦听器直接链接到实用程序函数的原因)这涉及 execute
本身内的 execute
调用。此时我只是 link to pastebin,但它抛出类型错误,因为它无法从嵌套的 execute
中取回值,因此它最终尝试调用 null.then
:
(node:6796) UnhandledPromiseRejectionWarning: TypeError: pInnerPromise.then is not a function
我如何构造我的代码,以便它在继续之前正确地等待 fetchMessages 查询,但仍然允许递归调用包装函数(或其他一些管道方式)?
您的代码
if (executable(sInnerCom) == true) {
// here you are using await so promise is already resolved.
let pInnerPromise = await execute(sInnerCom, pChannel);
// no need to use then, you can return result direct
pInnerPromise.then(result => { sInnerComResult = result });
}
应该是这样的
if (executable(sInnerCom) == true) {
let result = await execute(sInnerCom, pChannel);
sInnerComResult = result ;
}
或者像这样
if (executable(sInnerCom) == true) {
sInnerComResult = await execute(sInnerCom, pChannel);
}