javascript - TypeScript 装饰器中的异步调用

标签 javascript typescript unit-testing jestjs decorator

提前抱歉,任务太长了。我试图尽可能清楚地说明我面临的问题。

我创建了一个decorators utils library我在使用其中一个装饰器时遇到了奇怪的行为( https://github.com/vlio20/utils-decorators/blob/master/src/after/after.ts )。

装饰器被命名为“after”,它应该在执行装饰方法后执行不同的函数。但事情是这样的,如果函数返回一个 Promise,装饰器应该等待它被解析,然后才调用 after func。

相关代码如下:

        if (resolvedConfig.wait) {
          const response = await originalMethod.apply(this, args);
          afterFunc({
            args,
            response
          });
        } else {
          const response = originalMethod.apply(this, args);
          afterFunc({
            args,
            response
          });
        }

正如你所看到的,我为装饰器提供了一个标志,以指示装饰方法是一个异步函数,并且它返回一个 Promise。我很乐意通过以下代码来阅读此标志:

        const response = await originalMethod.apply(this, args);
          afterFunc({
            args,
            response
          });

基本上,我希望始终在执行原始方法之前放置 await ,因为根据我的理解,在同步方法的情况下,await 不会执行任何操作。

问题在于,当我按照上面的建议更改代码时,以下单元测试失败:

  it('should verify after method invocation when method is provided', () => {
    let counter = 0;

    const afterFunc = jest.fn(() => {
      expect(counter).toBe(1);
    });

    class T {

      @after<T, void>({
        func: afterFunc
      })
      foo(x: number): void {
        return this.goo(x);
      }

      goo(x: number): void {
        expect(counter++).toBe(0);

        return;
      }
    }

    const t = new T();
    const spyGoo = jest.spyOn(T.prototype, 'goo');

    t.foo(1);
    expect(spyGoo).toBeCalledTimes(1);
    expect(spyGoo).toBeCalledWith(1);
    expect(afterFunc.mock.calls.length).toBe(1); // this line fails
  });

我创建了该库的一个分支,但该精确测试失败了 ( https://github.com/vlio20/utils-decorators/pull/new/after-issue )。

我的认知有什么问题吗?

最佳答案

Basically, I want to always put await before the execution of the original method, as from my understanding in case of sync method the await doesn't do anything.

这不是真的。 According to the AsyncFunction reference on MDN (它本身直接引用 ECMAScript 规范),任何表示为 async 的函数将始终使函数体在常规调用序列之外执行。

换句话说,被调用者对 async/await 函数并不重要,它总是异步解析。这很重要,因为理想情况下函数应该只 ever be synchronous or asynchronous并且永远不会两者兼而有之。这体现在异步函数的返回类型中:它们总是产生一个promise,无论它们内部发生什么,并且promise永远不能被同步检查。

实现此目的的唯一方法是完全避免使用 await/async 并直接检查函数的返回类型:

const after = ({ func }) => (f) => (..args) => {
  const value = f(...args)
  if ('then' in value === false) {
    func()
    return value 
  }

  return value.then(value => {
    func()
    return value
  })
}

正如您可能从这个答案(以及我的引用文献)的语气中看出的那样,我认为这不是一个好的方法。建议保持您的函数完全同步或异步。

关于javascript - TypeScript 装饰器中的异步调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60402390/

相关文章:

javascript regexp 帮助传入一个 var 作为匹配的一部分

javascript - 用户名输入 If Else block 无法正常工作/Javascript - jQuery - AJAX

oop - 派生类的不同构造函数签名

javascript - 删除递归对象条目

java - 如何使用 Junit 和超时获得成功?

javascript - 下拉选择->搜索数据库

typescript - 强制子类在重写的方法中调用 super

java - 在抽象类中模拟 protected 方法

ios - Xcode 7 UI 测试失败 : App accessibility isn't loaded

javascript - 在文本框中留出空间