【问题标题】:technical difference between ES7 async function and a promise?ES7 异步函数和 Promise 之间的技术区别?
【发布时间】:2016-04-16 20:16:51
【问题描述】:

我试图更好地理解 JavaScript 中的 async function 在技术上是什么意思,即使我基本上知道如何使用它们。

许多对 async/await 的介绍让人相信 async 函数基本上只是一个承诺,但显然情况并非如此(至少 Babel6-transpiled code 不是):

async function asyncFunc() {
  // nop
}

var fooPromise = new Promise(r => setTimeout(r, 1));

console.clear();

console.log("typeof asyncFunc is", typeof asyncFunc); // function
console.log("typeof asyncFunc.next is", typeof asyncFunc.next); // undefined
console.log("typeof asyncFunc.then is", typeof asyncFunc.then); // undefined

console.log("typeof fooPromise is", typeof fooPromise); // object
console.log("typeof fooPromise.next is", typeof fooPromise.next); // undefined
console.log("typeof fooPromise.then is", typeof fooPromise.then); // function

不过,await 是绝对可能的,比如await fooPromise()

  • async funtion 是它自己的东西吗?await 只是兼容承诺?

  • 还有,有没有办法在运行时区分简单的 functionasync function(以 Babel 兼容的方式)?

【问题讨论】:

    标签: javascript babeljs ecmascript-next


    【解决方案1】:

    异步函数是一个返回承诺的函数。它可以帮助您处理大量异步操作一个接一个发生的情况:

    function asyncFunc() {
      return doSomethingAsync() // doSomethingAsync() returns a promise
        .then(() => {
          // do some stuff
          return doSomethingElseAsync(); // returns a promise
        })
        .then(something => {
          // do some stuff
          return doSomethingElseEntirelyAsync(something); // returns a promise
        });
    }
    

    转向

    async function asyncFunc() {
      await doSomethingAsync(); // awaits for a promise
      // do some stuff
      let something = await doSomethingElseAsync(); // awaits for a promise
      // do some stuff
      return doSomethingElseEntirelyAsync(something); // returns the final promise
      // Note that even if you return a value, like return 5, the function as a whole
      // still returns a promise!
    }
    

    它读起来好多了,即使它们是异步的,您也可以使用 try/catch 和 for 循环等普通工具来处理它们。

    异步函数不能替代 promise,它们是它们之上的糖,用于处理您有许多顺序异步操作的特定情况。

    因为await 基本上只是“等待这个promise”,你仍然可以使用Promise.all()Promise.race() 等很酷的聚合方法并等待几个(或几个)promise 的结果。

    我不熟悉在运行时区分两者的方法,因为与类一样,异步函数只是 Promises 之上的糖。 (虽然可能会有一些技巧,比如使用函数的.toString 并解析结果,但我不计算这些)。

    【讨论】:

    • 谢谢,很有意义。所以,本质上,asyncFunc 不是 Promise,但 asyncFunc() 是 - 或者换句话说:typeof asyncFunc().then == "function"
    【解决方案2】:

    async/await 是一种机制,可让您以同步方式编写异步代码,在我看来,这是迄今为止处理异步代码最简单易读的语法(另请参阅 this article)。语法的强大之处在于await 的工作方式。但是为了在函数体内使用await,函数必须以async 为前缀。

    如果您需要更多信息,请联系spec for async/await here

    Babel 5 中的当前实现基于https://github.com/facebook/regenerator。正如您在transpiled code 中看到的,该函数被编译为:

    function asyncFunc(which, one, two) {
      return regeneratorRuntime.async(function asyncFuncMaybe$(context$1$0) {
    ...
    

    如果你在 Babel 的 babel-regenerator-runtime 包中挖掘,你会找到 Facebook 的代码。在line 205,您会发现:

    // Note that simple async functions are implemented on top of
    // AsyncIterator objects; they just return a Promise for the value of
    // the final result produced by the iterator.
    runtime.async = function(innerFn, outerFn, self, tryLocsList) {
    ...
    

    为了转译到 ES5,async/await Babel 需要重新排列代码,以便我们可以在函数执行期间跟踪我们的位置,AsyncIterator 是跟踪该状态的对象。

    Babel 6 为您提供了更多选择,让您选择您想要使用的实现。见Transpile Async Await proposal with Babel.js?

    所以关于你的问题:

    • async/await 都是它自己的东西。根据规范,他们必须使用 Promise。特别是你可以在一个承诺上await,当你执行一个async函数时,它会返回一个承诺。
    • 由于async 函数被转换为返回promise 的函数,因此没有直接的方法将它与返回promise 的非异步函数区分开来。 你的fooPromise 应该看起来更像var fooPromiseFunc = function() {return new Promise(r => setTimeout(r, 1))};,这使得fooPromiseFuncasyncFunc 与黑匣子的预期没有区别。它们都是返回承诺的函数。您想在运行时区分 async 和 no-async 函数的原因是什么?在实践中,它们可以以相同的方式使用,所以我不明白为什么你必须以不同的方式威胁它们。出于调试目的,如果您确实需要确定函数是否定义 async,在 Babel 5 中,您可以使用类似 (asyncFunc+"").indexOf('regeneratorRuntime.async') > 0 或更准确的正则表达式。但这真的是 hacky,我不会在调试或研究之外的环境中使用。

    【讨论】:

    • 感谢您的深入解释。 Re: 你为什么要在运行时区分async和no-async函数的原因是什么?:其实我只是想区分普通回调和Promise(最终使expressPromise/以自动方式异步兼容)。现在我知道了事情是如何工作的,这一切对我来说都很清楚,实际上我能够为express 创建一个完美工作的(实验性)补丁。
    • 您可能会发现这两个链接很有用:strongloop.com/strongblog/…github.com/luin/express-promise
    • 感谢这些链接。我在发布这个问题之前就已经知道他们了,在答案的帮助下,我找到了一种避免使用显式包装函数并且仍然得到完全相同的结果的方法。
    猜你喜欢
    • 2012-05-05
    • 2021-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-01
    • 2021-10-16
    • 2013-02-19
    • 1970-01-01
    相关资源
    最近更新 更多