How to programmatically find if a function is async?

我的未来我决定 提交于 2019-12-24 01:24:07

问题


I am trying to override (monkey patch) the it() function of the Jasmine framework and in the process, I want to know if a function which is passed as the second argument to the it() function is of type async or not. I tried using the instanceof Promise because all async functions return a promise, but it never resolves to true and it never goes into the if block in the following code block. I have tried logging all the functions to the console and I found that all the async() function specs have a return type of tslib_1.awaiter(some args..).

Here is what I have:

let newIt = jasmine.getEnv().it;
jasmine.getEnv().it = function(...args): jasmine.Spec {
  // do something.
 if(args[1] instanceOf Promise) {
   debugger; // never comes in here.
   // catch error.
 }
 return newIt.apply(this, arguments);
}

What am I doing wrong here? Could anyone please point me into a right direction?

Thank you.

Edit: Let's say I have the following two dummy specs, one is async and the other is synchronous:

Async Test:

const exp = () => {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    resolve(1);
                }, 500);
            });
        };

 it('asyncTest', async () => {
      expect(await exp()).toEqual(1);
  }, 600);

Synchronous:

it('testNon', () => {
     expect(true).toBe(true);
 });

回答1:


This is XY problem. As pointed in this answer there is usually no need to check that it's async function because this doesn't matter. async function is just a function that returns a promise. Both () => Promise.resolve() and async () => {} should be treated in same way.

This is confirmed by the fact that it's impossible to distinguish between async and regular function in transpiled TypeScript code - both of them are just regular functions.

args[1] instanceOf Promise is incorrect, because a function won't be an instance of Promise. Monkey-patching is generally performed this way (this isn't specific to Jasmine or this case):

let newIt = jasmine.getEnv().it;
jasmine.getEnv().it = function(...args): jasmine.Spec {
  const fn = args[1];
  let newFn;
  if (fn.length > 0) {
    // async spec with done param
    newFn = function (done) {
      const result = fn.call(this, done);
      if(result instanceOf Promise)
      // or even better,
      // if(result && typeof result.then === 'function')
        debugger;
      return result;
    }
  } else {
    newFn = function () {
      const result = fn.call(this);
      if(result instanceOf Promise)
        debugger;          
      return result;
    }
  }

  args[1] = newFn;
  return newIt.apply(this, args);;
}

It's test function result that should be checked to be an instance of Promise (or to be checked if it's thenable).




回答2:


This isn't working because the async functions always return a promise, but they aren't in themselves promises.

The simple answer is to look at the constructor of the function in question (but I'll explain why you shouldn't after):

const isAsync = func.constructor.name === 'AsyncFunction';

The problem with this approach is that async functions aren't really meant to be distinguishable from regular functions which return a promise. It would be better to use Promise.resolve to turn the result of any function call into a Promise, and await that.



来源:https://stackoverflow.com/questions/49060405/how-to-programmatically-find-if-a-function-is-async

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!