javascript 回调在不可能的调用中被调用两次

标签 javascript typescript mocha.js

我构建了一个 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/

相关文章:

javascript - mocha-webpack 找不到测试

javascript - 具有不同 y 轴/刻度的分组条形图

javascript - 组合/合并可观察对象

javascript - 在同一对象的函数中访问变量

node.js - npm glob 模式与子目录不匹配

javascript - 在 mocha 测试中指定敏感信息

javascript - Object.getOwnPropertyNames 与 Object.keys

javascript - 如何在javascript函数中使用javascript变量作为html输入名称?

Javascript:历史记录未加载页面

javascript - Angular 6 UI 在不使用父模板的情况下实现更改检测