在JavaScript getter中调用数据库查询是否合理?实现疑问咨询
问题分析与解决方案
一、当前getter实现的问题
你的getter返回的是一个立即执行的异步函数(IIFE),本质上是返回了一个Promise。这意味着每次访问article.content时,你拿到的不是实际的内容字符串,而是一个Promise对象,必须用await或者.then()才能获取到值:
// 正确调用方式 const content = await article.content;
如果直接使用article.content,得到的会是Promise实例,这大概率和你预期的“属性”行为不符。另外,catch块里只打印错误但未抛出,会导致Promise变成resolved状态且值为undefined,调用方无法感知错误。
二、多数据库连接场景的适配
当前代码直接依赖全局的ArticleModel,这种硬编码方式无法支持多数据库连接。解决思路是把数据库模型/连接实例注入到Article类中,而非依赖全局变量:
方案1:构造函数传入模型
class Article { constructor(info, articleModel) { this._id = info.id; this._content = info.content; this._articleModel = articleModel; // 注入对应数据库的模型 } async getContent() { // 改用异步方法,而非getter try { const query = { id: this._id }; const artData = await this._articleModel.findOne(query); return artData.content; } catch (err) { console.error(err); throw err; // 抛出错误让调用方处理 } } } // 使用示例 const db1ArticleModel = getDb1ArticleModel(); // 从数据库1获取模型 const article1 = new Article({ id: 1 }, db1ArticleModel); const db2ArticleModel = getDb2ArticleModel(); // 从数据库2获取模型 const article2 = new Article({ id: 1 }, db2ArticleModel);
方案2:工厂函数创建实例
class Article { constructor(info, articleModel) { this._id = info.id; this._articleModel = articleModel; } async getContent() { try { const artData = await this._articleModel.findOne({ id: this._id }); return artData.content; } catch (err) { console.error(err); throw err; } } // 工厂方法,传入数据库连接生成实例 static async create(id, dbConnection) { const articleModel = dbConnection.model('Article'); const initialData = await articleModel.findOne({ id }); return new Article({ id, content: initialData?.content }, articleModel); } } // 使用示例 const db1Conn = getDb1Connection(); const article1 = await Article.create(1, db1Conn);
三、属性与行为的区别
- 属性:描述对象的状态,通常是对象自身持有的数据,比如
this._id是Article对象的固有属性,值相对稳定,不会每次访问都触发外部操作。 - 行为:对象执行的动作,比如从数据库获取最新内容,这是带有副作用(数据库请求)的主动操作,更适合用方法(比如
getContent())实现,而非getter属性。
用getter封装数据库请求的问题:
- 违背属性语义,调用方可能误以为访问的是本地缓存数据,而非每次都发起请求
- 异步getter不符合常规属性的同步预期,容易引发隐性bug
总结
- 将异步数据库查询改为明确的异步方法,替换当前的getter实现
- 通过注入模型/连接实例的方式,适配多数据库场景
- 明确区分属性(状态)和行为(操作),用对应逻辑封装功能
内容的提问来源于stack exchange,提问作者eruc
相关产品推荐
相关产品推荐

