连接完成后承诺不解决

Posted

技术标签:

【中文标题】连接完成后承诺不解决【英文标题】:Promise not resolving after connection completes 【发布时间】:2020-05-04 17:45:23 【问题描述】:

我有一个猫鼬连接功能,如果第一次尝试失败,我会尝试等待重新连接:

async connect() 
    const options = ...
    try 
        console.log("starting")
        await this._connectWithRetry(options)
        console.log("finished")
     catch (err) 
        winston.error(`Could not connect to Mongo with error: $err`)
    


private async _connectWithRetry(options) 
    return new Promise( async (resolve, reject) => 
        try 
            winston.info("Connecting to mongo...")
            await mongoose.connect(this.dbURI, options)
            winston.info("Connection successful.")
            resolve()
         catch (err) 
            winston.info("Failed to connect to mongo. Retrying in 5 seconds...")
            setTimeout( async () => 
                await this._connectWithRetry(options)
            , 5000)
        
    )

它成功地等待我连接。但是一旦我连接,第二条控制台线就不会被击中(“完成”)。所以我认为我的承诺解决方案是错误的。我做错了什么?

【问题讨论】:

提示:Promise.resolve()resolve() 不同。此外,如果连接失败,递归调用将创建一个新的 Promise,而原来的 Promise 也会消失而没有解决,所以这不好。 Promise.resolve() 返回一个新的已解决承诺。但是,如果您调用 resolve() 参数,您将解决它所属的承诺 如果您进入catch,那么您将永远不会解决也不会拒绝您创建的第一个承诺。如果第二次调用成功,那么您将解决一个不同的承诺,而第一个仍处于未决状态。 尝试从 Promise( async (resolve, reject) just Promise( (resolve, reject)) 中移除异步。这是我的猜测 ;) Never pass an async function as the executor to new Promise! 【参考方案1】:

如果第一次建立与数据库的连接,您的代码“有效”。

如果使用重试机制,你会看到你描述的错误。

第一次调用mongoDBConnect 实例化的Promise 在重试执行路径中永远不会被解析。

这是因为mongoDBConnect 的后续调用是在事件循环的未来滴答声中完全独立的执行上下文中进行的,由setTimeout 控制 - 并且每次调用都会实例化一个新的Promise 与您的@ 完全断开连接987654326@函数。

这种重构应该可以解决问题:

const delay = (interval) => new Promise(resolve => setTimeout(resolve, interval))

async connect() 
    const options = ...
    try 
        console.log("starting")
        await this._connectWithRetry(options)
        console.log("finished")
     catch (err) 
        winston.error(`Could not connect to Mongo with error: $err`)
    


private async _connectWithRetry(options) 
    try 
        winston.info("Connecting to mongo...")
        await mongoose.connect(this.dbURI, options)
        winston.info("Connection successful.")
     catch (err) 
        winston.info("Failed to connect to mongo. Retrying in 5 seconds...")
        await delay(5000)
        await this._connectWithRetry(options)
    

测试工具:

let retryCount = 0

const mongoose = 
    connect: ()=>retryCount++ === 2 ? Promise.resolve() : Promise.reject('fake error')


async function connect() 
    try 
        console.log("starting")
        await connectWithRetry()
        console.log("finished")
     catch (err) 
        console.error(`connect error`, err)
    


async function connectWithRetry() 
    try 
        console.log("Connecting to mongo...")
        await mongoose.connect()
        console.log("Connection successful.")
     catch (err) 
        console.log("Retrying in 1 second...", err)
        await delay(1000)
        await connectWithRetry()
    


const delay = (interval) => new Promise(resolve => setTimeout(resolve, interval))

connect()

【讨论】:

_connectWithRetry()return this._connectWithRetry(options) 内部(通常)比await this._connectWithRetry(options) 更有意义。在这种情况下,我们可以不使用await,因为我们只依赖于返回的 Promise 的结算,而不是它提供结果的能力。

以上是关于连接完成后承诺不解决的主要内容,如果未能解决你的问题,请参考以下文章

如何等到承诺完成后再继续循环

MySql安装完成后,Navicat连接不上的问题

ftp连接不上怎么解决啊,如下图

如何在 Node js 中承诺一个 mysql 池连接?

电脑连接不上服务器远程桌面,如何解决?

如何让我的 Node.js MySQL 连接作为承诺工作?