ES7异步功能和promise之间的技术差异

technical difference between ES7 async function and a promise?

本文关键字:技术 之间 promise 异步 功能 ES7      更新时间:2023-09-26

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

许多对async/await的介绍使人们相信async函数基本上只是一个承诺,但事实显然并非如此(至少对于Babel6传输的代码来说不是这样):

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只是与promise兼容?

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

异步函数是一个返回promise的函数。它可以帮助您处理一系列异步操作相继发生的情况:

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

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

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

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

async/await是一种机制,可以让您以同步风格编写异步代码,在我看来,这是迄今为止处理异步代码最简单、可读性最强的语法(另请参阅本文)。语法的力量实际上在于await的工作方式。但是,为了在函数体中使用await,函数必须以async为前缀。

如果您需要更多信息,这里有async/await的规范。

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

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

如果你深入挖掘Babel的babel-regenerator-runtime包,你会发现Facebook的代码。在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为您提供了更多的选项,让您可以选择想要使用的实现。请参阅Babel.js的Transpile Async Await提案?

关于你的问题:

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