【问题标题】:NodeJS Using decorators with a singleton class does not save the state of the class after initNodeJS 在单例类中使用装饰器并不会在初始化后保存类的状态
【发布时间】:2020-12-01 23:00:58
【问题描述】:

我有一个包含字典的类 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()将该类标记为单例

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

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

【问题讨论】:

  • 你能告诉我你是如何在路由文件中导入MongoQueryResolver 的吗?此外,使用这些export default new class 通常不是一个好主意,因为这被认为是一种反模式。 read more herehere
  • 根据我的记忆编辑,现在没有这台电脑上的源代码,但这是主要思想,我只是想了解为什么它不能这样工作
  • 你能说明.register().resolve()是如何实现的吗?

标签: node.js express decorator


【解决方案1】:

经过一段时间的调试,我发现了问题。

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

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

装饰器

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

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

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

为了解决这个问题,我必须检查注册函数是否存在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]() 来运行该函数。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-02-13
    • 2018-04-28
    • 1970-01-01
    • 2011-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多