如何以编程方式查找函数是否异步?

时间:2018-03-01 23:28:13

标签: javascript typescript jasmine

我试图覆盖(猴子补丁)Jasmine框架的it()函数,在这个过程中,我想知道一个函数是否作为第二个参数传递给it()函数是async类型。我尝试使用instanceof Promise,因为所有async函数都返回一个promise,但它永远不会解析为true,它永远不会进入下面代码块中的if块。我已经尝试将所有函数记录到控制台,我发现所有async()函数规范的返回类型都为tslib_1.awaiter(some args..)

这就是我所拥有的:

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);
}

我在这里做错了什么?有人可以指出我正确的方向吗?

谢谢。

编辑:我们说我有以下两个虚拟规格,一个是异步,另一个是同步:

异步测试:

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

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

同步:

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

2 个答案:

答案 0 :(得分:1)

这是XY问题。正如this answer中所指出的,通常无需检查它是async函数,因为这无关紧要。 async函数只是一个返回promise的函数。 () => Promise.resolve()async () => {}都应该以同样的方式对待。

事实证明,在转换的TypeScript代码中无法区分async和常规函数 - 这两者都只是常规函数。

args[1] instanceOf Promise不正确,因为函数不是Promise的实例。 猴子修补通常以这种方式执行(这不是特定于Jasmine或这种情况):

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);;
}

它的测试函数结果应该被检查为Promise的实例(或者如果它是可以检查的话)。

答案 1 :(得分:0)

这不起作用,因为异步函数总是返回一个承诺,但它们本身并不承诺。

简单的答案是查看相关函数的构造函数(但我将解释为什么你不应该在之后):

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">

  <!--<view class="us.sam.views.ButtonBar$LabeledButton$Button"-->
  <ImageView  
    android:id="@+id/ButtonBar_LabeledButton_ButtonImageView"
    style="@style/ButtonBar_LabeledButton_ButtonImageView"/>
  <!--android:src="@drawable/v__ic_add_circle_outline_black_24dp"-->

  <!--view class="us.sam.views.ButtonBar$LabeledButton$Label"-->
  <TextView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ButtonBar_LabeledButton_LabelTextView"
    style="@style/ButtonBar_LabeledButton_LabelTextView"/>
  <!--android:text="Add New"-->

</merge>

这种方法的问题在于,异步函数实际上并不能与返回promise的常规函数​​区分开来。最好使用public class LabeledButton : LinearLayout { private ImageView _buttonIV; private TextView _labelTV; private int _buttonIV_src; private string _labelTV_text; public LabeledButton(Context context, IAttributeSet attributes) : base(context, attributes) { ReadAttributes(context, attributes); } private void ReadAttributes(Context context, IAttributeSet attributes) { Android.Content.Res.TypedArray typedArray = context.ObtainStyledAttributes(attributes, Resource.Styleable.LabeledButton); _buttonIV_src = typedArray.GetResourceId(Resource.Styleable.LabeledButton_button_imageview_src, 0); _labelTV_text = typedArray.GetString(Resource.Styleable.LabeledButton_label_textview_text); typedArray.Recycle(); } protected override void OnFinishInflate() { base.OnFinishInflate(); _buttonIV = FindViewById<ImageView>(Resource.Id.ButtonBar_LabeledButton_ButtonImageView); _labelTV = FindViewById<TextView>(Resource.Id.ButtonBar_LabeledButton_LabelTextView); _buttonIV.SetImageResource(_buttonIV_src); _labelTV.Text = _labelTV_text; } } 将任何函数调用的结果转换为const isAsync = func.constructor.name === 'AsyncFunction'; Promise.resolve