Discord.js - 尝试等待异步进程并允许递归调用包装器

Posted

技术标签:

【中文标题】Discord.js - 尝试等待异步进程并允许递归调用包装器【英文标题】:Discord.js - Trying to both await an async process and allow recursive calls of a wrapper 【发布时间】:2019-07-04 14:57:35 【问题描述】:

这个有很多活动部件,我已尝试尽可能简化它们,而且我仍在学习异步/等待处理,所以请耐心等待 -

所以我正在尝试使用 discord.js 为 Discord 聊天机器人编写聊天命令。我遇到问题的命令由以!aut 开头的消息触发,应该接受用户输入字符串(在命令本身之后)并返回另一个字符串;如果用户没有提供字符串,我希望它在包含命令的消息上方(即第二个最近的)抓取消息的内容并将其用作输入字符串。

但是,在测试后一种情况时,它会不断抛出此错误: (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 是异步的 - 或者至少返回一个 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 查询,但仍允许递归调用包装函数(或其他管道方式)?

【问题讨论】:

【参考方案1】:

你的代码

    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); 
    

【讨论】:

以上是关于Discord.js - 尝试等待异步进程并允许递归调用包装器的主要内容,如果未能解决你的问题,请参考以下文章

异步函数 discord.js 中的 awaitMessages

如何在异步函数 discord.js 中使用 message.react() 中的循环

discord.js bot await 仅在异步函数中有效

Discord JS,等待消息,不同的输入

Discord JS bot 如何从 API 获取递归异步函数

Discord.js 作为机器人获取用户连接