【问题标题】:How to handle error properly with nested promises in different modules如何使用不同模块中的嵌套承诺正确处理错误
【发布时间】:2020-01-09 05:24:49
【问题描述】:

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

我有一个调用 db.js 的模块,它带有一个用于设置和启动 db 连接的 init 函数:

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)
})}

这个函数会返回一个promise,它会被index.js调用:

initDb()
.then(() => {
    app.listen(8081, function () {
        console.log('App is running on port 8081')
    })
})
.catch((error) => {
    console.log(error)
})

如您所见,我有两个问题。一个在 db 模块中,另一个在 index.js 中

在两个地方捕获错误看起来很奇怪......在这种情况下处理错误的好模式是什么?

【问题讨论】:

  • 你为什么要设置一个新的 Promise,里面有一个 Promise?如果我正确阅读了您的代码,client.connect 也会返回一个承诺

标签: javascript node.js express error-handling promise


【解决方案1】:

您需要避免使用Promise constructor antipattern。也不要将database 本身存储在变量中,而是存储它的承诺。

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;
}

【讨论】:

  • 谢谢,非常有趣的帖子!我只有一个问题。我目前拥有的是 initDb() 来连接 db 对象并将其存储在变量中,以及另一个函数: getDb() ,用于检索 DB 对象,因此我可以将其导入其他模块并非常轻松地使用它。但是您提到不要存储数据库对象。但是,如果我存储了承诺,那么我就失去了轻松调用数据库的能力。代码将如下所示: getDb().then((db) => { return db.collection('foo').find() }) ,而不仅仅是 getDb().collection.find() 。我错过了什么吗?
  • 您如何确保数据库调用代码仅在连接初始化后才运行?也许不是拥有可以在任何地方导入的getDb 函数,而是使db 成为需要它的函数的显式参数。 (也适用于控制反转)
【解决方案2】:

如果db.js模块的initDb函数中不写catch,可以在调用函数中catch那个错误,所以不写.catch((err) => {reject( err)}) 在 db.js 模块中,错误将转到 index.js 中的调用函数,您可以直接在那里处理。

在这两个地方都捕获错误并不奇怪,事实上在即将到来的节点版本中,这将是编写 catch(err) 来处理所有 promise 的错误的推荐做法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-23
    • 2020-02-19
    • 2018-12-03
    • 2020-04-11
    • 2019-12-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多