ES7 异步函数和承诺之间的技术区别?

technical difference between ES7 async function and a promise?

我试图更好地理解 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()

异步函数是 函数,returns 承诺。它可以帮助您解决一系列异步操作接连发生的情况:

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 循环来处理它们,即使它们是异步的。

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

因为 await 基本上只是 "await for this promise",你仍然可以使用像 Promise.all()Promise.race() 这样的酷聚合方法并等待几个(或几个)承诺中的第一个。

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

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

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

Babel 5 中的当前实现是基于https://github.com/facebook/regenerator. As you can see in the transpiled code 函数被编译为:

function asyncFunc(which, one, two) {
  return regeneratorRuntime.async(function asyncFuncMaybe$(context[=10=]) {
...

如果你深入挖掘 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 给了你更多的选择,让你选择你想使用的实现。参见

所以关于你的问题:

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