如何知道函数是否异步?

时间:2016-07-21 15:32:20

标签: javascript node.js async-await ecmascript-next

我必须将一个函数传递给另一个函数,并将其作为回调执行。问题是有时这个函数是异步的,比如:

async function() {
 // Some async actions
}

所以我想执行await callback()callback(),具体取决于它所接收的函数类型。

有没有办法知道函数的类型??

8 个答案:

答案 0 :(得分:41)

原生async功能可以识别when being converted to strings

asyncFn[Symbol.toStringTag] === 'AsyncFunction'

AsyncFunction构造函数:

const AsyncFunction = (async () => {}).constructor;

asyncFn instanceof AsyncFunction === true

这不能与Babel / TypeScript输出一起使用,因为asyncFn在转换代码中是常规函数,它是FunctionGeneratorFunction的实例,而不是{{1 }}。确保它不会在转换代码中为生成器和常规函数提供误报

AsyncFunction

问题显然是指const AsyncFunction = (async () => {}).constructor; const GeneratorFunction = (function* () => {}).constructor; (asyncFn instanceof AsyncFunction && AsyncFunction !== Function && AsyncFunction !== GeneratorFunction) === true 函数的Babel实现,它依赖transform-async-to-generatorasync转换为生成函数,也可以使用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实现的任何函数,而不只是asyncthe solution to said Angular problemasync包裹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或更高版本

使用native util function

   util.types.isAsyncFunction(function foo() {});  // Returns false
   util.types.isAsyncFunction(async function foo() {});  // Returns true

但是请不要忘记回答所有的问题。刚偶然返回一个承诺的函数将返回一个假阴性。

最重要的(来自文档):

  

请注意,这只会报告JavaScript引擎正在显示的内容;特别是,如果使用了翻译工具,则返回值可能与原始源代码不匹配。

但是,如果您在NodeJS 10中使用async,并且不进行任何交易。这是一个很好的解决方案。

答案 4 :(得分:2)

TL; DR

简答:在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";

干杯!