我正在努力更好地理解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兼容?以及,有没有一种方法可以在运行时区分简单的
function
和async 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))};
,使fooPromiseFunc
和asyncFunc
与黑匣子无法区分。它们都是返回承诺的函数。您想在运行时区分async
和无异步函数的原因是什么?在实践中,它们可以以相同的方式使用,所以我不明白为什么你必须以不同的方式威胁它们。出于调试目的,如果您真的需要了解函数是否定义为async
,那么在Babel 5中,您可以使用类似(asyncFunc+"").indexOf('regeneratorRuntime.async') > 0
或更准确的正则表达式。但事实上hacky和我不会在调试或研究之外的上下文中使用