理论
本机async 函数可能是可识别的when being converted to strings:
asyncFn[Symbol.toStringTag] === 'AsyncFunction'
或者通过AsyncFunction构造函数:
const AsyncFunction = (async () => {}).constructor;
asyncFn instanceof AsyncFunction === true
这不适用于 Babel/TypeScript 输出,因为 asyncFn 是转译代码中的常规函数,它是 Function 或 GeneratorFunction 的实例,而不是 AsyncFunction。为了确保它不会在转译代码中为生成器和常规函数提供误报:
const AsyncFunction = (async () => {}).constructor;
const GeneratorFunction = (function* () => {}).constructor;
(asyncFn instanceof AsyncFunction && AsyncFunction !== Function && AsyncFunction !== GeneratorFunction) === true
由于原生 async 函数是在 2017 年正式引入 Node.js 的,所以这个问题可能是指 async 函数的 Babel 实现,它依赖于 transform-async-to-generator 将 async 转换为生成器函数,也可以使用transform-regenerator 将生成器转换为常规函数。
async 函数调用的结果是一个承诺。 According to the proposal,promise 或 non-promise 可以传递给await,所以await callback() 是通用的。
只有少数情况下可能需要这样做。例如,原生 async 函数在内部使用原生 Promise,如果其实现发生更改,则不会选择全局 Promise:
let NativePromise = Promise;
Promise = CustomPromiseImplementation;
Promise.resolve() instanceof Promise === true
(async () => {})() instanceof Promise === false;
(async () => {})() instanceof NativePromise === true;
这可能会影响函数行为(这是Angular and Zone.js promise implementation 的一个已知问题)。即使这样,最好检测函数返回值不是预期的Promise 实例而不是检测函数是async,因为同样的问题适用于任何使用替代承诺实现的函数,而不仅仅是async (@ 987654327@ 是将async 返回值与Promise.resolve 包装在一起。
练习
从表面上看,async 函数只是一个无条件返回原生 promise 的函数,因此它应该被视为一个函数。即使一个函数曾经被定义为async,它也可以在某个时候被转译并成为常规函数。
一个可以返回承诺的函数
在 ES6 中,可能返回 promise 的函数可以与 Promise.resolve(允许同步错误)或包装 Promise 构造函数(处理同步错误)一起使用:
Promise.resolve(fnThatPossiblyReturnsAPromise())
.then(result => ...);
new Promise(resolve => resolve(fnThatPossiblyReturnsAPromiseOrThrows()))
.then(result => ...);
在 ES2017 中,这是通过 await 完成的(问题中的示例应该是这样写的):
let result = await fnThatPossiblyReturnsAPromiseOrThrows();
...
应该返回一个承诺的函数
检查一个对象是否是一个承诺是a matter of a separate question,但通常它不应该太严格或太松以涵盖极端情况。如果全局 Promise 被替换 Promise !== (async () => {})().constructor,instanceof Promise 可能无法工作。当 Angular 和非 Angular 应用程序接口时,可能会发生这种情况。
一个需要async的函数,即总是返回一个promise应该首先被调用,然后返回值被检查为一个promise:
let promise = fnThatShouldReturnAPromise();
if (promise && typeof promise.then === 'function' && promise[Symbol.toStringTag] === 'Promise') {
// is compliant native promise implementation
} else {
throw new Error('async function expected');
}
TL;DR:async 函数不应与返回承诺的常规函数区分开来。没有可靠的方法也没有实际的理由来检测非本地转译的async 函数。