我必须将一个函数传递给另一个函数,并将其作为回调执行。问题是有时这个函数是异步的,比如:
async function() {
// Some async actions
}
所以我想执行await callback()
或callback()
,具体取决于它所接收的函数类型。
有没有办法知道函数的类型??
答案 0 :(得分:41)
原生async
功能可以识别when being converted to strings:
asyncFn[Symbol.toStringTag] === 'AsyncFunction'
或AsyncFunction
构造函数:
const AsyncFunction = (async () => {}).constructor;
asyncFn instanceof AsyncFunction === true
这不能与Babel / TypeScript输出一起使用,因为asyncFn
在转换代码中是常规函数,它是Function
或GeneratorFunction
的实例,而不是{{1 }}。确保它不会在转换代码中为生成器和常规函数提供误报:
AsyncFunction
问题显然是指const AsyncFunction = (async () => {}).constructor;
const GeneratorFunction = (function* () => {}).constructor;
(asyncFn instanceof AsyncFunction && AsyncFunction !== Function && AsyncFunction !== GeneratorFunction) === true
函数的Babel实现,它依赖transform-async-to-generator
将async
转换为生成函数,也可以使用transform-regenerator
将生成器转换为常规函数功能
async
函数调用的结果是一个承诺。 According to the proposal,承诺或非承诺可以传递给async
,因此await
具有普遍性。
只有少数边缘情况可能需要。例如,原生await callback()
函数在内部使用本机承诺,如果其实现发生更改,则不会选择全局async
:
Promise
这可能会影响功能行为(这是Angular and Zone.js promise implementation的已知问题)。即使这样,最好检测到函数返回值不是预期let NativePromise = Promise;
Promise = CustomPromiseImplementation;
Promise.resolve() instanceof Promise === true
(async () => {})() instanceof Promise === false;
(async () => {})() instanceof NativePromise === true;
实例,而不是检测函数是Promise
,因为同样的问题适用于使用备选promise实现的任何函数,而不只是async
(the solution to said Angular problem将async
包裹async
返回值。
TL; DR:Promise.resolve
函数不应与返回promises的常规函数区分开来。在这种情况下,它们当然不应该被区分。没有可靠的方法也没有理由去检测非原生的async
函数。
答案 1 :(得分:17)
@rnd和@estus都是正确的。
但要在这里用实际工作解决方案回答这个问题,你可以去
function isAsync (func) {
const string = func.toString().trim();
return !!(
// native
string.match(/^async /) ||
// babel (this may change, but hey...)
string.match(/return _ref[^\.]*\.apply/)
// insert your other dirty transpiler check
// there are other more complex situations that maybe require you to check the return line for a *promise*
);
}
这是一个非常有效的问题,我很沮丧,有人拒绝投票给他。此类检查的主要用途是用于库/框架/装饰器。
这些是早期版本,我们不应该低估 VALID 问题。
答案 2 :(得分:11)
我喜欢这种简单的方法:
theFunc.constructor.name == 'AsyncFunction'
答案 3 :(得分:5)
如果您使用的是NodeJS 10.x或更高版本
util.types.isAsyncFunction(function foo() {}); // Returns false
util.types.isAsyncFunction(async function foo() {}); // Returns true
但是请不要忘记回答所有的问题。刚偶然返回一个承诺的函数将返回一个假阴性。
最重要的(来自文档):
请注意,这只会报告JavaScript引擎正在显示的内容;特别是,如果使用了翻译工具,则返回值可能与原始源代码不匹配。
但是,如果您在NodeJS 10中使用async
,并且不进行任何交易。这是一个很好的解决方案。
答案 4 :(得分:2)
简答:在exposing instaceof
后使用AsyncFunction
- 见下文。
答案很长:不要这样做 - 见下文。
您可以使用async
关键字
创建函数时,它表明它是一个类型函数:
> f1 = function () {};
[Function: f1]
您可以使用instanceof
运算符对其进行测试:
> f1 instanceof Function
true
创建异步函数时,它表明它是AsyncFunction类型:
> f2 = async function () {}
[AsyncFunction: f2]
所以可以预期它也可以使用instanceof
进行测试:
> f2 instanceof AsyncFunction
ReferenceError: AsyncFunction is not defined
为什么?因为AsyncFunction不是全局对象。请参阅文档:
即使如您所见,它列在Reference/Global_Objects
...
如果您需要轻松访问AsyncFunction
,那么您可以使用我的unexposed
模块:
获取局部变量:
const { AsyncFunction } = require('unexposed');
或添加全局AsyncFunction
以及其他全局对象:
require('unexposed').addGlobals();
现在上面的工作正如预期的那样:
> f2 = async function () {}
[AsyncFunction: f2]
> f2 instanceof AsyncFunction
true
上面的代码将测试函数是否是使用async
关键字创建的,但请记住,真正重要的不是函数是如何创建的,而是函数是否返回一个promise。
你可以在任何地方使用这个" async"功能:
const f1 = async () => {
// ...
};
你也可以用这个:
const f2 = () => new Promise((resolve, reject) => {
});
即使它不是使用async
关键字创建的,因此也不会与instanceof
或与其他答案中发布的任何其他方法相匹配。
具体来说,请考虑一下:
const f1 = async (x) => {
// ...
};
const f2 = () => f1(123);
f2
只有f1
带有硬编码的参数,在这里添加async
没有多大意义,即使结果会是那么多"异步"在每个方面都为f1
。
因此可以检查某个函数是否是使用async
关键字创建的,但请谨慎使用,因为当您检查它时,您很可能会做错事。
答案 5 :(得分:2)
似乎await
也可以用于正常功能。我不确定是否可以将其视为“良好做法”,但这是:
async function asyncFn() {
// await for some async stuff
return 'hello from asyncFn'
}
function syncFn() {
return 'hello from syncFn'
}
async function run() {
console.log(await asyncFn()) // 'hello from asyncFn'
console.log(await syncFn()) // 'hello from syncFn'
}
run()
答案 6 :(得分:0)
您可以在开始时就假设回调是应许的:
export async function runSyncOrAsync(callback: Function) {
let promisOrValue = callback()
if (promisOrValue instanceof Promise) {
promisOrValue = Promise.resolve(promisOrValue)
}
return promisOrValue;
}
并且在您的代码中可以执行以下操作:
await runSyncOrAsync(callback)
这将在不知道回调类型的情况下解决您的问题。...
答案 7 :(得分:0)
Hei
这是David Walsh在其blogpost中提供的一种方法:
const isAsync = myFunction.constructor.name === "AsyncFunction";
干杯!