首页 > 解决方案 > 作用域方法装饰器到一个类的实例

问题描述

我正在尝试使用方法装饰器构建一个简单的缓存。

假设我有以下课程:

class Contract {
  constructor(public readonly contractAddress: string) {}

  @cache()
  async getBalance(): Promise<number> {
    // Get balance for this.contractAddress from a backend and return it
    return balance
  }
}

我目前有以下缓存装饰器:


const promiseCache = new Map<string, Promise<unknown>>()

const cache = () => {
  return (_target: Object, propertyKey: string, descriptor: PropertyDescriptor) => {
    const originalMethod = descriptor.value

    descriptor.value = async function (...args: any[]) {
      const constructedKey = constructKey(args)
      const promise = promiseCache.get(constructedKey)
      if (promise) {
        return promise
      } else {
        const newPromise = originalMethod.apply(this, args)
        promiseCache.set(constructedKey, newPromise)
        return newPromise
      }
    }

    return descriptor
  }
}

如果我只有这个类的一个实例,这很好用。但是,如果我创建一个不同的第二个实例contractAddress,那么缓存似乎是相同的。

// Example

const a = new Contract('a') // has balance of 1
const b = new Contract('b') // has balance of 2

await a.getBalance() // returns 1
await b.getBalance() // returns 1

我试图找到这个问题的答案,但我发现的唯一一件事是无法将类的实例传递给装饰器,因此我无法访问contractAddress以将其添加到我的密钥中。

我还尝试将“promiseCache”放入装饰器工厂,但这也不起作用。

我尝试的最后一件事是向装饰器工厂添加一个参数,但这也没有用。

// THIS DOES NOT WORK

const cache = (id: number) => { ... }

@cache(Math.random())
getBalance() { ... }
// This gave me a random number in the decorator, but it seemed to be the same one per method across all instances

// or 

@cache(this.contractAddress) // This doesn't even compile
getBalance() { ... }

这可能吗?我看到的唯一两个解决方案是不使用装饰器并在每个方法中添加缓存(由于额外的样板,我想避免这种情况),或者将 contractAddress 作为每个方法的参数传递,这也不是很好.

标签: javascripttypescriptdecorator

解决方案


推荐阅读