【问题标题】:JS async/await - why does await need async?JS async/await - 为什么 await 需要异步?
【发布时间】:2017-10-26 07:27:18
【问题描述】:

为什么使用await需要将其外部函数声明为async

例如,为什么这个 mongoose 语句需要它所在的函数来返回一个承诺?

async function middleware(hostname, done) {
  try {
    let team = await Teams.findOne({ hostnames: hostname.toLowerCase() }).exec();
    done(null, team);
  } catch (err) { done(err); }
}

我看到运行时/转译器将 Teams 承诺解析为它的值,并异步发出信号,它“抛出”被拒绝的承诺。

但是 try/catch “捕捉”了那些被拒绝的承诺,那么为什么 async 和 await 如此紧密耦合?

【问题讨论】:

  • 我不明白您所说的“但 try/catch “捕获”那些被拒绝的承诺”是什么意思。这与async 关键字有什么关系?
  • 为什么这个 mongoose 语句需要它所在的函数来返回一个承诺?” - 否则它如何能够等待 mongoose 承诺的异步结果?
  • 这里是语言设计的原因:stackoverflow.com/a/41744179/1483977

标签: javascript asynchronous async-await


【解决方案1】:

因为在middleware 函数中使用await 意味着middleware 函数不能立即返回结果(它必须等到await 解决)并且middleware 函数调用者必须等到promise(返回来自middleware函数)已解决。

【讨论】:

    【解决方案2】:

    由@phaux 复制自https://stackoverflow.com/a/41744179/1483977

    这些答案都给出了为什么 async 关键字是 好东西,但他们都没有真正提到它的真正原因 必须添加到规范中。

    原因是这是一个有效的 JS pre-ES7

    function await(x) {
      return 'awaiting ' + x
    }
    
    function foo() {
      return(await(42))
    }
    

    根据您的逻辑,foo() 会返回 Promise{42} 还是 "awaiting 42"? (返回一个 Promise 会向后中断 兼容性)

    所以答案是:await 是一个常规标识符,它只是 被视为异步函数中的关键字,因此必须对其进行标记 以某种方式。

    有趣的事实:原始规范为异步语法提出了更轻量级的function^ foo() {}

    【讨论】:

    • 但是await的使用不是需要空格吗?我的意思是,如果 await 只是一个变量,像 var a = await foo() 这样的代码可以有效吗?
    • 为什么 foo() 会返回“等待 42”?很明显,它会。不是为了实际的等待,我猜 return await(somePromise) 会在返回解决方案之前等待一些 Promise 解决。或者至少这似乎是一个有用的速记。但实际上这样的延迟回报基本上是一个承诺。好的,知道了。
    • @user405205​​4 是的,但await (expressionThatEvaluatesToAPromise) 是等待承诺的有效语法结构,await (5) 是将参数5 传递给用户定义函数await 的有效方式.
    【解决方案3】:

    我不参与 JavaScript 语言设计讨论,但我认为与 the C# language requires async 的原因相同(另请参阅 my blog)。

    即:

    1. 向后兼容性。如果await 突然成为无处不在的新关键字,那么任何使用await 作为变量名的现有代码都会中断。由于await 是上下文关键字(由async 激活),只有打算await 用作关键字的代码才会将await 用作关键字。
    2. 更容易解析。 async 使异步代码更易于为转译器、浏览器、工具和人类解析。

    【讨论】:

    • 我认为这两个论点都不能解释为什么使用await 需要函数是异步的。 更容易解析从来都不是语言设计的好论据。它必须更容易学习和编程,解析器是一个程序,应该承担繁重的工作。可以通过使用任何关键字来修复向后兼容性,以防止旧的await 符号停止工作而不将函数从同步更改为异步。
    • 确实没有理由需要异步。您仍然可以使用同步函数并通过循环实现自己的 await 直到 Promise 被解决,从而有效地使父函数和被调用函数全部同步。我读过其他答案,原因是为了避免阻塞主事件循环,但是您同步执行的所有操作都会这样做,有什么好处?
    • @Petruza:不过,您必须允许其他代码运行,否则承诺将永远无法解决。
    • @Petruza:目标是更易于维护的代码。在可维护性方面,await > then > 回调。
    • @Petruza:在大多数环境中,异步优于同步,因为它释放了主线程。在浏览器中,同步代码会冻结 UI。在服务器上,同步代码阻止处理其他请求。如果您正在编写命令行进程/脚本,那么同步代码是可以的,异步或同步成为个人喜好问题。但是,即使在那种环境中,如果需要,异步也允许并发。
    猜你喜欢
    • 1970-01-01
    • 2019-04-05
    • 1970-01-01
    • 1970-01-01
    • 2015-06-30
    • 1970-01-01
    • 2017-05-02
    • 2019-05-10
    相关资源
    最近更新 更多