我构建了一个 TS,MongoDB 客户端包装器。由于某种原因,当我调用获取连接的函数时,它的回调被调用两次。
总共有 2 次对 get() 函数的调用,如您所见,一次在导出之前,另一次来自 Mocha 测试。
总的来说,我对 TS 和 JS 还很陌生,但这似乎有点不对劲。
import {Db, MongoClient} from "mongodb"; import {MongoConfig} from '../config/config' class DbClient { private cachedDb : Db = null; private async connectToDatabase() { console.log('=> connect to database'); let connectionString : string = "mongodb://" + MongoConfig.host + ":" + MongoConfig.port; return MongoClient.connect(connectionString) .then(db => { console.log('=> connected to database'); this.cachedDb = db.db(MongoConfig.database); return this.cachedDb; }); } public async get() { if (this.cachedDb) { console.log('=> using cached database instance'); return Promise.resolve(this.cachedDb); }else{ return this.connectToDatabase(); } } } let client = new DbClient(); client.get(); export = client;
控制台输出是:
=> connect to database => connected to database => connected to database
这种行为不当有什么具体原因吗?
最佳答案
There are 2 calls in total to the get() function, 1 before the export as you can see and another from a mocha test.
我怀疑输出有一个额外的=>连接到数据库
。正如我在评论中所说:有一个“竞争条件”,在设置 this.cachedDb
之前可以多次调用 get()
,这将导致多个连接/实例正在创建的数据库的数量。
例如:
const a = client.get();
const b = client.get();
// then
a.then(resultA => {
b.then(resultB => {
console.log(resultA !== resultB); // true
});
});
解决方案
可以通过将 Promise 存储为缓存值来解决这个问题(而且,正如 Randy 指出的那样,不需要在方法上使用 async
关键字,因为在任何方法中都没有等待值)方法,这样你就可以返回 promise ):
import {Db, MongoClient} from "mongodb";
import {MongoConfig} from '../config/config'
class DbClient {
private cachedGet: Promise<Db> | undefined;
private connectToDatabase() {
console.log('=> connect to database');
const connectionString = `mongodb://${MongoConfig.host}:${MongoConfig.port}`;
return MongoClient.connect(connectionString);
}
get() {
if (!this.cachedGet) {
this.cachedGet = this.connectToDatabase();
// clear the cached promise on failure so that if a caller
// calls this again, it will try to reconnect
this.cachedGet.catch(() => {
this.cachedGet = undefined;
});
}
return this.cachedGet;
}
}
let client = new DbClient();
client.get();
export = client;
注意:我不确定使用 MongoDB 的最佳方式(我从未使用过它),但我怀疑连接不应该太长,以至于像这样缓存(或者应该只缓存短时间后断开连接)。不过,您需要对此进行调查。
关于javascript 回调在不可能的调用中被调用两次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56527492/