Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/413.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
javascript回调在一次不可能的调用中被调用两次_Javascript_Typescript_Mocha.js - Fatal编程技术网

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

javascript回调在一次不可能的调用中被调用两次,javascript,typescript,mocha.js,Javascript,Typescript,Mocha.js,我构建了一个TS、MongoDB客户机包装器。出于某种原因,当我调用获取连接的函数时,它的回调函数会被调用两次 总共有两个get()函数调用,一个在导出之前调用,另一个在mocha测试中调用 总的来说,我对TS和JS还很陌生,但这似乎有点不对劲 其中,控制台输出为: 有没有什么特别的原因导致这种行为不端 总共有两个get()函数调用,一个在导出之前调用,另一个在mocha测试中调用 我怀疑输出有一个额外的连接到数据库的=>。正如我在评论中所说:存在一个“竞争条件”,其中get()可以在之前被多次

我构建了一个TS、MongoDB客户机包装器。出于某种原因,当我调用获取连接的函数时,它的回调函数会被调用两次

总共有两个get()函数调用,一个在导出之前调用,另一个在mocha测试中调用

总的来说,我对TS和JS还很陌生,但这似乎有点不对劲

其中,控制台输出为:

有没有什么特别的原因导致这种行为不端

总共有两个get()函数调用,一个在导出之前调用,另一个在mocha测试中调用

我怀疑输出有一个额外的连接到数据库的
=>。正如我在评论中所说:存在一个“竞争条件”,其中
get()
可以在
之前被多次调用。设置cachedDb
将导致创建多个Db连接/实例

例如:

const a = client.get();
const b = client.get();

// then
a.then(resultA => {
    b.then(resultB => {
        console.log(resultA !== resultB); // true
    });
});
解决方案

这个问题可以通过将承诺存储为缓存值来解决(同样,正如Randy指出的,方法上不需要使用
async
关键字,因为在任何方法中都没有等待的值,所以您可以只返回承诺):

从“mongodb”导入{Db,MongoClient};
从“../config/config”导入{MongoConfig}
类DbClient{
私人纪念印:承诺|未定义;
私有连接数据库(){
log('=>connecttodatabase');
const connectionString=`mongodb://${MongoConfig.host}:${MongoConfig.port}`;
返回MongoClient.connect(connectionString);
}
得到(){
如果(!this.cachedGet){
this.cachedGet=this.connectToDatabase();
//在失败时清除缓存的承诺,以便
//再次调用此,它将尝试重新连接
this.cachedGet.catch(()=>{
this.cachedGet=未定义;
});
}
返回此.cachedGet;
}
}
让client=newdbclient();
client.get();
导出=客户端;
注意:我不确定使用MongoDB的最佳方式(我从未使用过它),但我怀疑连接不应该像这样被缓存(或者应该只缓存一段时间,然后断开连接)。不过你需要调查一下

总共有两个get()函数调用,一个在导出之前调用,另一个在mocha测试中调用

我怀疑输出有一个额外的连接到数据库的
=>。正如我在评论中所说:存在一个“竞争条件”,其中
get()
可以在
之前被多次调用。设置cachedDb
将导致创建多个Db连接/实例

例如:

const a = client.get();
const b = client.get();

// then
a.then(resultA => {
    b.then(resultB => {
        console.log(resultA !== resultB); // true
    });
});
解决方案

这个问题可以通过将承诺存储为缓存值来解决(同样,正如Randy指出的,方法上不需要使用
async
关键字,因为在任何方法中都没有等待的值,所以您可以只返回承诺):

从“mongodb”导入{Db,MongoClient};
从“../config/config”导入{MongoConfig}
类DbClient{
私人纪念印:承诺|未定义;
私有连接数据库(){
log('=>connecttodatabase');
const connectionString=`mongodb://${MongoConfig.host}:${MongoConfig.port}`;
返回MongoClient.connect(connectionString);
}
得到(){
如果(!this.cachedGet){
this.cachedGet=this.connectToDatabase();
//在失败时清除缓存的承诺,以便
//再次调用此,它将尝试重新连接
this.cachedGet.catch(()=>{
this.cachedGet=未定义;
});
}
返回此.cachedGet;
}
}
让client=newdbclient();
client.get();
导出=客户端;

注意:我不确定使用MongoDB的最佳方式(我从未使用过它),但我怀疑连接不应该像这样被缓存(或者应该只缓存一段时间,然后断开连接)。不过,您需要对此进行调查。

旁注:存在一个竞争条件,在此条件下,
get
可以在
之前被多次调用。设置cachedDb
将导致创建多个连接/实例
Db
。这可以通过将
connectToDatabase
的承诺分配给私有属性,然后在
get
中返回该承诺来避免(不过它可能会以某种方式处理失败)。您的承诺逻辑有缺陷。除了David的建议之外,
get()
方法还返回封装在承诺中的承诺或封装在承诺中的已解析承诺(
this.cachedDb
)。但是不要使用任何一个。您从
MongoClient.connect()
返回承诺,但从不使用它(然后从
get
返回)。最后,在promise上使用then并返回一个从未使用过的值。也许你应该回顾一下@RandyCasburn中非常简单的设计,我看不到该代码中有任何包含在承诺(承诺返回承诺)中的承诺。也许我遗漏了什么?@David-
connectToDatabase()
是异步的,并返回一个Promise对象,该Promise对象由
get()
直接返回,还有一个异步函数,它返回一个封装在承诺中的承诺。@Gleeb-检查这一点,这是以更简洁的方式编写的类。旁注:有一个竞争条件,在这个条件下,
get
可以在
之前被多次调用。cachedDb
被设置,这将导致
Db
的多个连接/实例被激活创建。这可以通过将
connectToDatabase
的承诺分配给私有属性,然后在
get
中返回该承诺来避免(不过它可能会以某种方式处理失败)。您的承诺逻辑有缺陷。除了什么,大卫
const a = client.get();
const b = client.get();

// then
a.then(resultA => {
    b.then(resultB => {
        console.log(resultA !== resultB); // true
    });
});
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;