如何在 JS(节点)中使用回调等待异步函数完成后再继续?

How to use callback in JS (node) to wait for Async function to finish before proceeding?

我有一个名为 t运行slateCommand(command) 的函数,它使用从 npm 到 t运行slate 的 T运行slate 包将一些文本转换成不同的语言。问题是该包提供的 t运行slate 函数是异步的,它倾向于在 t运行slate 函数完成之前退出 t运行slateCommand 函数,导致 return 的垃圾数据。

我发现它完成得太快了,并使 t运行slateCommand(command) 成为一个异步函数,这样我就可以在导入的 t运行slate() 前面使用 await函数,它解决了那个问题,但现在我只是将问题进一步推迟了一步,因为调用 t运行slateCommand(command) 的函数遇到了完全相同的问题,我觉得我没有做如果我只需要继续向上重复这个链条,就会取得进展。

事实是,我并不真正了解 Promises 以及异步函数与它们相关的一般行为方式。我意识到这是使 Node.js 伟大的前提,但试图了解它却相当无效。试图解决这个问题并没有真正取得成果,因为每个人都只是说使用回调而没有解释回调到底是什么。这些示例通常被不熟悉的代码所包围,这无济于事,因此我认为在我的代码上下文中获得帮助将一举两得。

这整个过程是我制作一个愚蠢的 Discord Bot 的介绍性尝试,我在其中实现了一堆愚蠢的功能。我已经 运行 多次进入异步墙,但通常会找到一个同步的替代方案来继续前进。这次我没有,我尝试模拟其他 Stack Overflow 帖子中描述的回调,但由于缺乏理解,无法正确集成它们(我只能假设)。

顶级导入函数现在有异步问题。

client.on("message", (message) => {

    // ...
    let command = (message.content).substr(1);

    // ...

    // Handles translate command
    else if (command.startsWith("translate"))
        message.channel.send(translateCommand(command));

    // ...
    }
});

异步的函数,因此它可以等待:

// Form !translate [string]
async function translateCommand(command) {
    let message = "";
    let str = command.substr(10);

    await translate(str, { to: 'ja', engine: 'yandex', key: '<my key>' }).then(function(result) {
        message = result;
        return "";
    });
    return message;
}

我知道这个问题已经被问死了,但我觉得在没有上下文的情况下我理解了(因为我对 JS 和 Node 都是新手),我只能用头撞墙来继续直到有些东西在我不明白为什么的情况下起作用。

您也可以将顶级函数更改为异步函数。将开头更改为 async (message) => { 并使用 message.channel.send(await translateCommand(command))。或者,您可以选择使用 promises 而不是使函数异步,而是使用 translateCommand(command).then(msg => message.channel.send(msg)),但是它可能会在后面的代码中弄乱流程。

因为 translate return 是您不需要做出的承诺 translateCommand async。只需从函数 return translate...

function translateCommand(command) {
  let str = command.substr(10);
  return translate(str, { to: 'ja', engine: 'yandex', key: '<my key>' });
}

...和 ​​await 解决的承诺。您需要将 async 添加到事件处理程序回调中才能使 await 正常工作。

client.on("message", async (message) => {

  let command = (message.content).substr(1);

  //...

  else if (command.startsWith("translate"))
    message.channel.send(await translateCommand(command));
    // ...
  }
});

使用承诺,您可以执行以下操作:

translateCommand 函数:

var translateCommand = (command) => new Promise((resolve,reject) =>  {
    translate(command.substr(10), { to: 'ja', engine: 'yandex', key: '<my key>' })
        .then(resolve)
        .catch(reject)
    });

然后 client.on:

client.on("message", (message) => {

    // ...
    let command = (message.content).substr(1);

    // ...

    // Handles translate command
    else if (command.startsWith("translate"))
        translateCommand(command)
            .then(translationResult => {
               message.channel.send(translationResult)
            })
    // ...
    }
});

如果您对语法有疑问,请参考以下提示:
hint #1
hint #2
+ 一句话 - 不要害怕,花点时间阅读 + 实现上面的示例并在之后修改它们以导致错误(你将知道它们如何以及何时工作或不工作 - 痛苦但有益;))