【问题标题】:trying to understand async / await / sync in node试图理解节点中的异步/等待/同步
【发布时间】:2022-02-12 00:56:45
【问题描述】:

我知道这可能以前被问过,但是在过去的 20 年里,我来自单线程语言,我真的很难掌握 node.js 的真正本质。相信我,我已经阅读了很多关于此的 SO 帖子、github 讨论和文章。

我想我理解每个函数都有它自己的线程类型的交易。但是,在某些情况下,我希望我的代码完全同步(一个接一个地触发一个函数)。

例如,我做了 3 个函数,它们似乎向我展示了节点的异步 i/o 是如何工作的:

function sleepA() {
    setTimeout(() => {
        console.log('sleep A')
    }, 3000)
}

function sleepB() {
    setTimeout(() => {
        console.log('sleep B')
    }, 2000)
}

function sleepC() {
    setTimeout(() => {
        console.log('sleep C')
    }, 1000)
}

sleepA()
sleepB()
sleepC()

这会输出以下内容:

sleep C
sleep B
sleep A

好的,这是有道理的。节点同时触发所有功能,并且首先完成的功能会被记录到控制台。有点像看赛马。节点开枪,函数起飞,最快的获胜。

所以现在我将如何使这些同步,以便顺序始终为 A、B、C,而不管 setTimeout 数字如何?

我已经涉足bluebirdutil 节点库之类的东西,但我仍然有点困惑。我认为这种异步逻辑非常强大,尽管我无法真正掌握它。 php毁了我的心。

【问题讨论】:

  • @Teemu - 好吧,除非您明确使用诸如工作进程或子进程之类的东西。 :-) “明确地”是那里的关键词。
  • "我将如何使这些同步,以便顺序始终为 A、B、C" 你的意思是:我如何不启动 B 超时,直到超时结束?在 B 完成之前不启动 C?
  • @T.J.Crowder 是的。
  • JavaScript 是单线程语言

标签: javascript node.js


【解决方案1】:

我将如何使这些同步,以便顺序始终为 A、B、C

您已确认您的意思是您不想在 A 完成(等等)之前开始 B 的超时。

在 2021 年,最简单的方法是为 setTimeout 使用启用了承诺的包装器,如下所示:

const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));

然后,制作sleepAasync 之类的函数:

async function sleepA() {
    await delay(3000);
    console.log("sleep A");
}

async function sleepB() {
    await delay(2000);
    console.log("sleep B");
}

async function sleepC() {
    await delay(1000);
    console.log("sleep C");
}

那么你的代码可以await每个函数返回的promise,这会阻止代码继续直到promise被解决:

await sleepA();
await sleepB();
await sleepC();

您可以在 async 函数内或(在现代版本的 Node.js 中)在模块的顶层执行此操作。您不能在同步函数中使用await,因为await 本质上是异步的。

我想我明白每个函数都有自己的交易线程类型

不,JavaScript 函数与其他同步语言的函数一样(尽管它享有盛誉,但 JavaScript 本身绝大多数是同步的;它只是在高度异步的环境中使用,并且最近获得了一些使其更容易的特性)。更多内容请参见下文。

好的,这是有道理的。节点同时触发所有功能,并且首先完成的功能会被记录到控制台。有点像看赛马。节点开枪,函数起飞,最快的获胜。

关闭。这些函数按顺序运行,但它们每个所做的只是设置一个计时器并返回。他们不等待计时器触发。稍后,当它触发时,它会调用您传递给 setTimeout 的回调。

JavaScript 有一个 主线程 并且一切都在那个主线程上运行,除非你明确地让它在工作线程或子进程中运行。 Node.js 是高度异步的(就像 web 浏览器一样,其他地方 JavaScript 最常用),但你的 JavaScript 代码默认都在一个线程上运行。有一个处理“工作”的循环。作业按事件(例如计时器触发)排队,然后由事件循环按顺序处理。我在 here 上进行了更多讨论,Node.js 文档涵盖了他们的循环 here (我认为它有点过时了,但主体没有改变)

【讨论】:

  • FWIW,我在我最近一本书 JavaScript: The New Toys 的第 8 章中详细介绍了 Promise,其中涵盖了 ES2015-ES2020,并进入了 async/await in第 9 章中的详细信息。如果您有兴趣,请访问我的个人资料中的链接。
  • 谢谢你这个答案正是我在寻找我的问题。您清晰的示例和解释非常有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-26
  • 2016-12-26
  • 2018-10-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多