NodeJS 在单例 class 中使用装饰器不会在初始化后保存 class 的状态

NodeJS Using decorators with a singleton class does not save the state of the class after init

我有一个 class MongoQueryResolver 其中包含一个字典:

private queries: {[key: string]: (params) => any} = {};

这个字典通过一个键保存函数,其中每个函数都是 MongoDB.

的查询函数

我创建了一个装饰器 MongoQuery,它表示一个 mongo 查询函数:

export function MongoQuery(queryName: string) {
    return function decorator(target, key, func) {
        target.register(queryName, func);
    }
}

此装饰器调用 MongoQueryResolver#register 以便在字典中注册查询,以便我可以通过查询名称使用它。

我创建的 MongoQuery 函数示例:

@MongoQuery(QueryType.GET_ALL_ENABLED)
public async getAllEnabled(params) {
    const workersDb = MongoService.getBranch(Branches.WORKERS).db("workers");
    const configCollection = await workersDb.collection('config');

    const criteria: any = {isEnabled: true};

    if (params.proxy) {
        criteria.proxy = params.proxy;
    }

    return await configCollection.find(criteria).toArray();
}

以及我如何在外面使用它:

MyRoutes.get('/get-enabled', async (req, res) => {
    const data = await MongoQueryResolver.resolve(QueryType.GET_ALL_ENABLED, {proxy: req.query.proxy});
    res.json(data);
});

问题

当我的应用程序启动时,我在现场打印字典:

set GET_ALL_ENABLED {
  value: [Function: getAllEnabled],
  writable: true,
  enumerable: false,
  configurable: true
}
{
  GET_ALL_ENABLED: {
    value: [Function: getAllEnabled],
    writable: true,
    enumerable: false,
    configurable: true
  }
}

但是当我开始使用字典时,它是空的..

我通过 export default new MongoQueryResolver()

将 class 标记为单例

为什么会这样?好像是新实例?

import MongoQueryResolver from '../../services/mongo/mongo-query-resolver'

调试了一段时间,问题解决了

发生这种情况有一个原因,我希望我是对的。

在开始之前,让我展示一个简单的小例子:

装饰器

export function MongoQuery(queryName: string) {
    return function decorator(target: any, key: any, func: any) {
        target.register(queryName, func);
    }
}

解析器单例

class Resolver {
     map: any;

    constructor() {
        this.map = {};
    } 
    
    register(queryName: any, func: any) {
        this.map[queryName] = func;
    }

    resolve(queryName: string) {
       this.map[queryName]();
    }

    @MongoQuery('myQuery')
    public testQuery() {
        console.log("test!");
    }
}
export default new Resolver();

index.ts

Resolver.resolve("myQuery");

这个例子的问题与我原来的例子非常相关,当装饰器 运行s 在 class 创建时, 它不会 运行 构造函数,也不初始化 class 变量(如果你在顶部做 map = {}

这意味着map只会在装饰器运行s之后设置。

为了解决这个问题,如果this.map存在,我将不得不检查寄存器函数,如果不存在,就设置它。

register(queryName: any, func: any) {
    this.map = this.map || {};
    this.map[queryName] = func;
}

现在我将永远拥有 map 属性 集。

现在唯一剩下的问题是 resolve 函数,当您将函数保存在字典中时,它看起来像这样:

 {
  value: [Function: testQuery],
  writable: true,
  enumerable: false,
  configurable: true
}

这就是我得到 is not a function 的原因,所以我必须 运行 this.map[queryName].value() 到 运行 函数而不是 this.map[queryName]()

希望这对任何人都有帮助!