【问题标题】:await still sets variable to undefined and setting returned or callbacked functions to global variablesawait 仍然将变量设置为未定义并将返回或回调函数设置为全局变量
【发布时间】:2021-01-10 05:52:43
【问题描述】:
    async function displayEmbed(args, msg) {
    var bridgeembed = await getBridgeClutcherStats(args, msg) //should set bridgeembed to an embed
    var omniembed = await getOmniClutcherStats(args, msg) //should set omniembed to an embed
    var extembed = await getExtClutcherStats(args, msg) //should set extembed to an embed

    var desccc = "```Bridge Clutch: ????```\n" + "```Omni Clutch: ⚛```\n" + "```Extension Clutch: ????```\n";
    new Menu(msg.channel, msg.author.id, [{
    name: "main",
    content: new MessageEmbed({
        title: "Please Choose a Gamemode",
        description: desccc,
        url: "https://3d4h.world",
        color: 16711935,
        author: {
            name: args[1],
            url: `https://namemc.com/profile/${args[1]}`,
            icon_url: `https://mc-heads.net/body/${args[1]}`
        }
    }),
    reactions: {
        "????": "stop",
        "????": "bridgeclutch",
        "⚛": "omniclutch",
        "????": "extclutch"
    }
},
{
    name: "bridgeclutch",
    content: bridgeembed,
    reactions: {
        "◀": "main"
},
    name: "omniclutch",
    content: omniembed,
    reactions: {
        "◀": "main"
    },
    name: "extclutch",
    content: extembed,
    reactions: {
        "◀": "main"
    }

}
]);

}

所以在创建嵌入菜单之前,我一直在尝试运行三个函数。我遵循了这些 (How to synchronously call a set of functions in javascript) 步骤,但 bridgeembed、omniembed 和 extembed 仍然以未定义的形式结束。

当我直接从函数发送嵌入时,它起作用了。我也尝试过使用这样的回调:

       getOmniClutcherStats(args, msg, function(omniclutchEmbed){

            getExtClutcherStats(args, msg, function(extclutchEmbed){

                getBridgeClutcherStats(args, msg, function(bridgeclutchEmbed) {

                    new Menu(msg.channel, msg.author.id, [{
                        name: "main",
                        content: new MessageEmbed({
                            title: "Please Choose a Gamemode",
                            description: desccc,
                            url: "https://3d4h.world",
                            color: 16711935,
                            author: {
                                name: args[1],
                                url: `https://namemc.com/profile/${args[1]}`,
                                icon_url: `https://mc-heads.net/body/${args[1]}`
                            }
                        }),
                        reactions: {
                            "????": "stop",
                            "????": "bridgeclutch",
                            "⚛": "omniclutch",
                            "????": "extclutch"
                        }
                    },
                    {
                        name: "bridgeclutch",
                        content: bridgeembed,
                         reactions: {
                            "◀": "main"
                       },
                        name: "omniclutch",
                         content: omniembed,
                         reactions: {
                            "◀": "main"
                          },
                        name: "extclutch",
                         content: extembed,
                         reactions: {
                            "◀": "main"
                        }
                
                    }
                    ]);
                
                
                });
        

            });
        });

但只有在桥接时它才有效,对于其他人UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'content' of undefined

如何将返回或回调的嵌入保存到变量中,以便在反应菜单中访问它们?

提前致谢!

【问题讨论】:

  • 为什么你的函数是嵌套的?你在哪里return他们的任何价值?
  • @O.Jones 我在函数内部返回(pastebin.com/Xzk4eQ9E 这是其中之一),我在第二次尝试中嵌套了回调。除非我错过了什么?
  • 对于初学者,await 仅在您等待承诺时才会做一些有用的事情。看到您在返回承诺上没有尝试使用 await 的任何功能,这显然是错误的。
  • @jfriend00 基本正确(尤其是在这种情况下)。更准确的心理模型是,如果返回类型是 Promiseawait 会准确返回函数返回的内容except,在这种情况下,它会执行直到 promise 解决。
  • @msbit - 这意味着除非它在等待一个承诺,否则它是没有意义的。很多人一开始就认为await 有超能力知道函数中的事情何时完成。它没有任何此类权力。它所做的只是对函数返回的承诺进行操作。如果没有承诺,它就没有任何用处——因为它只是通过不变的标准返回值。这是很多人(包括OP)需要学习的。

标签: javascript node.js asynchronous async-await discord.js


【解决方案1】:

正如@o-jones 和@jfriend00 所提到的,您需要直接从您的函数中返回一些内容,以便它们可以在displayEmbed 中使用。此外,正如@jfriend00 所提到的,如果您想使用async/await 来确保调用按顺序发生,您需要确保函数的返回类型是Promise,它将通过结果,或者结果本身,如果可以同步确定的话。

查看该 PasteBin 中为 getExtClutcherStats 提供的代码,您正在调用一些异步函数:

  • connection.query
  • MojangAPI.nameToUuid
  • MojangAPI.profile
  • average

全部使用 NodeJS 风格的回调传递模式。此外,在您的快乐路径中,您将返回嵌套在所有这些调用中的 extclutchembed

connection.query('SELECT * FROM C3', function (error, rows, fields) {
  …
  MojangAPI.nameToUuid(args[1], function (err, res) {
    …
    MojangAPI.profile(rows[playerNum].UUID, function (err, res) {
      …
      average(`/home/bardia/3d4hbot/${res.name}.png`, (err, color) => {
        …
        return extclutchEmbed
      }
      …
    }
    …
  }
  …
}

鉴于该结构,extclutchEmbed 将仅返回到立即回调函数(快乐路径中的average)。

在这种情况下,确保返回 Promise 的最快方法是将逻辑包装在传递给 Promise 构造函数的函数中,并将您希望在 promise 解析时返回的结果传递给resolve函数,像这样:

function getExtClutcherStats (args, msg) {
  …
  return new Promise((resolve, reject) => {
    …
    connection.query('SELECT * FROM C3', function (error, rows, fields) {
      …
      MojangAPI.nameToUuid(args[1], function (err, res) {
        …
        MojangAPI.profile(rows[playerNum].UUID, function (err, res) {
          …
          average(`/home/bardia/3d4hbot/${res.name}.png`, (err, color) => {
            …
            resolve(extclutchEmbed)
            return
          }
          …
        }
        …
      }
      …
    }
  });
}

您需要在该函数中处理return 的其他位置,以确保调用者可以处理它们,或者,如果您想将错误处理推送给调用者,您可以使用@987654344 @ 功能;例如,靠近顶部:

if (args[1].length > 16) {
  msg.channel.send('Invalid Player Name')
  return
}

可能变成:

if (args[1].length > 16) {
  reject('Invalid Player Name')
  return
}

然后调用站点可以变成:

try {
  var extembed = await getExtClutcherStats(args, msg)
} catch (error) {
  msg.channel.send(error);
}

【讨论】:

  • 由于某种原因我仍然遇到问题。这个:pastebin.com/xySa44Lx 是我的呼叫站点,而这个:pastebin.com/DRFsXK8p 是我的另一个得到相同处理的函数。 try/catch 中的最后一个函数 getExtClutcherStats 工作并将变量设置为嵌入,但是它们的 try/catch 中的第一个和第二个函数都将变量设置为未定义,除了一些小的更改之外,它们都是相同的,并且Promise 部分完全相同。你知道@msbit 发生了什么吗?
  • getBridgeClutcherStats 中,promise 无法通过多种方式解决 1) connection.query 遇到错误 2) MojangAPI.nameToUuid 遇到错误 3) foundPlayer 为假 4) MojangAPI.profile 遇到错误。如何处理这取决于您;我建议调用reject 并将错误传递给他们的回调(类似于args[1].length 检查)。此外,在displayEmbed 中,最好将所有可以抛出的代码以及所有依赖于它的代码放在单个try 块中。什么取决于你。
  • 同样的问题。功能:pastebin.com/4c8aLXTz。呼叫站点:pastebin.com/cF1iL6G8。虽然这样:pastebin.com/WCpb6NNm 函数确实将变量更改为嵌入。 @msbit 你发现有什么不同或其他问题吗?
  • displayEmbed 中,我建议将catch 块移到函数底部,因为您在对new Menu 的调用中使用了*embed 变量。然后,在该块中,添加对console log 的调用以注销除msg.channel.send 之外的所有错误。此时,您至少应该看到由于被拒绝的Promise 而导致的任何错误。如果您不这样做,则需要仔细考虑 get*Stats 函数中的代码路径;也许洒一些console.logs 来测试你关于代码如何运行的假设。
猜你喜欢
  • 2014-10-06
  • 2018-10-10
  • 2016-11-25
  • 2022-01-22
  • 1970-01-01
  • 2017-01-25
  • 1970-01-01
  • 1970-01-01
  • 2017-04-03
相关资源
最近更新 更多