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

Posted

技术标签:

【中文标题】如何在 JS(节点)中使用回调来等待 Async 函数完成后再继续?【英文标题】:How to use callback in JS (node) to wait for Async function to finish before proceeding? 【发布时间】:2019-09-19 14:44:42 【问题描述】:

我有一个名为 translateCommand(command) 的函数,它使用来自 npm 的 Translate 包将一些文本翻译成不同的语言。问题是该包提供的translate函数是异步的,往往在translate函数完成之前就退出translateCommand函数,导致返回垃圾数据。

我发现它完成太快是问题,并将 translateCommand(command) 设为异步函数,这样我就可以在导入的 translate() 函数前面使用 await,这解决了该问题,但现在我只是延迟了这个问题更进一步,因为调用 translateCommand(command) 的函数遇到了完全相同的问题,如果我只需要继续向上重复这个链,我觉得我没有取得任何进展。

事实上,我并不真正了解 Promise 以及 Async 函数在一般情况下与它们相关的行为方式。我意识到这是让 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) =&gt; message.channel.send(await translateCommand(command)); 【参考方案1】:

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

【讨论】:

client.on("message", async (message) =&gt; // ... ); 假设这是正确的隐含结构,由第一种方法建议(如果我错了,请纠正我)。此***函数中将使用消息的其他同步函数是否有任何后果?另外,您所说的 Promise 路由可能会在代码后面弄乱流程是什么意思?对不起,谢谢。【参考方案2】:

因为translate 返回一个你不需要做出translateCommand async 的承诺。只需从函数中返回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));
    // ...
  
);

【讨论】:

所以我可以完全废弃.then(function(result) message = result; return ""; ) 部分?同样作为后续,结果参数如何捕获 translate 的输出?非常抱歉,非常感谢。 您可以使用const message = await translate(...),而不是then,然后您将使用return message。但是你可能会错过这一步,而只是简单地返回承诺。在您的代码中,result 只是 resolve 函数中的数据(作为参数)。它可以被命名为任何东西。无论如何,给它一个测试,看看它是否适合你。 附言。您可以在this jsfiddle 中看到thenawait 之间的区别。【参考方案3】:

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

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 #1hint #2 + 一句话 - 不要害怕,花点时间阅读 + 实施上述示例并在之后修改它们以导致错误(您将知道它们如何以及何时工作或不工作 - 痛苦但有益;))

【讨论】:

感谢您提供另一种方法!了解解决此问题的所有方法确实很有帮助,也令人尴尬地验证了我对该主题的困惑,因为我认为我尝试了将所有这些解决方案混合在一起。按照您的提示,我刚刚意识到为什么我对箭头函数如此困惑(它们基本上是 Lambda 函数,对吗?),这是因为如果它们只有一个参数,您可以删除参数周围的括号,这让我永远感到困惑。 我已经很久没有接触C#了,但是是的,我认为fat arrow functions(因为他们在javascript中有那个有趣的名字)可以被认为是lambda expressions(至少在这个案例)。我很高兴能帮上忙。另外 - 是的,当它们采用单个参数时,可以省略括号(一个小缺点是它在声明具有不同数量参数的多个函数时引入了代码可读性“困难”[非统一语法])。 普通函数和箭头函数的主要区别在于箭头函数没有自己的thisarguments。它们从外部词法环境继承了 this,从而节省了将 this 分配给 self 或绑定的时间。 @Andy:没有人提到'normal' functions,但是lambdaarrow 一个 我解释了它们之间的区别。有什么问题?

以上是关于如何在 JS(节点)中使用回调来等待 Async 函数完成后再继续?的主要内容,如果未能解决你的问题,请参考以下文章

使用轴和 Vue.js 进行异步/等待调用 - `.then()` 回调未更新 `this.something`

js回调函数如何实现异步,给一个例子

异步/等待和任务

Node.js mongodb 驱动程序异步/等待查询

如何使用async.js简化Node.js中的回调代码

如何在JavaScript中使用async / await延迟数组回调?