Javascript 如何使用不同模块中的嵌套承诺正确处理错误

Javascript 如何使用不同模块中的嵌套承诺正确处理错误,javascript,node.js,express,error-handling,promise,Javascript,Node.js,Express,Error Handling,Promise,我是Node JS的新手,在使用promises时,我很难正确处理错误。 以下是我目前拥有的: 我有一个模块调用db.js,其中包含一个init函数,用于设置和启动db连接: function initDb(){ return new Promise((resolve, reject) => { if(database){ console.warn("Trying to init DB again !") }else{ client.conn

我是Node JS的新手,在使用promises时,我很难正确处理错误。 以下是我目前拥有的:

我有一个模块调用db.js,其中包含一个init函数,用于设置和启动db连接:

function initDb(){
return new Promise((resolve, reject) => {
    if(database){
        console.warn("Trying to init DB again !")
    }else{
        client.connect(config.db.url, {useNewUrlParser: true, useUnifiedTopology: true})
        .then((client) => {
            console.log("DB initialized - connected to database: " + config.db.name)
            database = client.db(config.db.name)
        })
        .catch((err) => {
            reject(err)
        })
    }
    resolve(database)
})}
此函数将返回一个承诺,并将其调用到index.js中:

initDb()
.then(() => {
    app.listen(8081, function () {
        console.log('App is running on port 8081')
    })
})
.catch((error) => {
    console.log(error)
})
正如你所看到的,我有两个陷阱。一个在db模块中,另一个在index.js中


在两个地方发现错误是很奇怪的。。。在这种情况下,处理错误的好模式是什么

如果您没有在db.js模块的initDb函数中写入catch,您可以在调用函数中捕获该错误,因此如果您没有在db.js模块中写入.catch((err)=>{reject(err)}),则错误将转到index.js中的调用函数,您可以直接在那里处理它

在两个位置捕获错误并不奇怪,事实上,在即将发布的node版本中,这将是一种推荐的做法,即编写捕获(err)来处理所有承诺中的错误。

您将希望避免错误。另外,不要将
数据库本身存储在变量中,而是存储它的承诺

let databasePromise;
function initDb() {
    if (databasePromise) {
        console.debug("DB already initialised");
        return databasePromise;
    }
    databasePromise = client.connect(config.db.url, {useNewUrlParser: true, useUnifiedTopology: true})
    .then((client) => {
        console.log("DB initialized - connected to database: " + config.db.name)
        return client.db(config.db.name)
    });
    return databasePromise;
}

为什么你要设定一个新的承诺,里面有一个承诺?如果我正确阅读了你的代码,client.connect也会返回一个承诺谢谢,非常有趣的帖子!我只有一个问题。我现在使用的是initDb()连接db对象并将其存储在变量中,还有另一个函数:getDb(),用于检索db对象,因此我可以在其他模块中导入该对象并非常轻松地使用它。但是您提到不要存储数据库对象。但是如果我存储了承诺,那么我就失去了轻松调用db的能力。代码将类似于:getDb().then((db)=>{return db.collection('foo').find()}),而不仅仅是getDb().collection.find()。我是否遗漏了什么?您如何确保数据库调用代码仅在连接初始化后运行?也许可以将
db
作为需要它的函数的显式参数,而不是使用
getDb
函数,您可以在任何地方导入它。(也适用于控制反转)