【问题标题】:Nodejs express promise.all().then() is not synchronousNodejs express promise.all().then() 不是同步的
【发布时间】:2020-09-18 07:43:44
【问题描述】:

我正在使用 Nodejs express 构建一个小应用程序,在其中更新/删除一些数据。完成更新/删除后,我想再次从数据库中返回数据。我使用 promise.all() 是因为我想让一切都成功或一起失败。

我的问题是它没有同步运行。我的代码时不时地在更新/删除发生之前返回数据。

这是一个例子:

const save = async (houseId, personIds, pets, petsToDelete) => {
    let dbActions = []

    personIds.forEach((personId) => {
        pets.forEach((pet) => {
            pet.ownerId = personId
        })
        dbActions.push(
            PetRepository.deletePets(personId, petsToDelete),
            PetRepository.updatePets(personId, pets),
        )
    })

    await Promise.all(dbActions)
    let promiseResult = await Promise.all([
           PetRepository.findByHouse({ houseId: houseId })
    ])

    return promiseResult
}

问题是 PetRepository.findByHouse 有时会在循环中的所有 dbAction 执行/完成之前返回数据。

我认为将它们添加到数组中并在循环外的 Promise.all 中使用该数组可以解决问题,但事实并非如此。有什么想法吗?

如何调用 save():

    const promiseResponseHandler = (req, res, promise) => {
        promise.then(successResponse(req, res)).catch(...errorhandling...)
    }

    App.put('save/:houseId', (req, res) => {
        promiseResponseHandler(req, res, PetService.save(req.params.houseId, req.body[0], req.body[1], req.body[2]))
    })

更新:存储库函数


const Mongoose = require('mongoose')
Mongoose.Promise = global.Promise

Mongoose.connection.on('open', () => Logger.info('Db connection established'))
let connectionString

connectionString = `mongodb+srv://${Config.MONGO_HOST}?retryWrites=true`

connection = Mongoose.connect(
    connectionString,
    {
        user: Config.MONGO_USER,
        pass: Config.MONGO_PW,
        dbName: Config.MONGO_DB,
        reconnectTries: 3,
        useNewUrlParser: true
    }
).catch((err) => {
    Logger.error(err)
})

const deletePets = async (personId, petsToDelete) => {
    if (petsToDelete.length > 0) {
        await Pet.bulkWrite(
            petsToDelete.map((petId) => {
                deleteMany: {
                    filter: { personId: personId, petId: petId}
                }
            })
        )
    }
}

const updatePets = async (personId, pets) => {
    if (pets.length > 0) {
        await Pet.bulkWrite(
            pets.map((pet) => ({
                updateOne: {
                    filter: { personId: pet.personId, petId: petId },
                    update: { 
                        $set: { name: pet.name },
                        $setOnInsert: { 
                            petId: pet.petId, 
                            personId: personId,
                            houseId: pet.houseId
                        } 
                    }
                }
            }))
        )
    }
}

module.exports = { deletePets, updatePets }

【问题讨论】:

  • 如果你不使用它,为什么要标记async/await

标签: javascript node.js express promise async-await


【解决方案1】:

您正在使用 thenables(回调)来解决这个问题。使用异步/等待会更容易。为了能够等待Promise.all,您需要将save 定义为异步函数,如下所示:

const save = async (houseId, personIds, pets, petsToDelete) => {
    let dbActions = []

    personIds.forEach((personId) => {
        pets.forEach((pet) => {
            pet.ownerId = personId
        })
        dbActions.push(
            PetRepository.deletePets(personId, petsToDelete),
            PetRepository.updatePets(personId, pets),
        )
    })

    await Promise.all(dbActions)
    let promiseResult = await PetRepository.findByHouse({ houseId: houseId })
    return promiseResult
}

然后您将继续等待保存,以确保在您继续之前完成。 当然,您也可以使用回调来执行此操作,将其传递给 save 方法,并在您的最终响应中调用它,如下所示:

const save = (houseId, personIds, pets, petsToDelete, callback) => {
    let dbActions = []

    personIds.forEach((personId) => {
        pets.forEach((pet) => {
            pet.ownerId = personId
        })
        dbActions.push(
            PetRepository.deletePets(personId, petsToDelete),
            PetRepository.updatePets(personId, pets),
        )
    })

    Promise.all(dbActions).then(()=>
        // callback gets called with the response of the promise
        PetRepository.findByHouse({ houseId: houseId }).then(callback)
    )
}

您必须记住,您不能只是将承诺分配给变量并期望它是结果。如果你这样做:

let result = Promise.all([promise1, promise2])

result 将包含一个承诺,因此为了获得值,您必须await it(内联)或then it(回调)

【讨论】:

  • 我尝试用您提出的异步解决方案替换thenables,但问题仍然存在。我添加了一个如何调用 save() 函数的示例。 promiseResult 仍然返回一些应该在 dbActions 承诺列表中更新或删除的数据。
  • 无论你在哪里调用一个承诺,你都确保await
  • 是的,我已经用新的实现更新了我的问题
  • 一切看起来都不错,唯一想到的是这些存储库函数是否正确返回了 Promise ?
  • 嗨,我已经用存储库函数代码更新了我的问题,你能看看吗?在 db 中,所有内容都按预期更新,只是在 dbActions 中的所有内容完成之前提前返回了 Save 函数PetRepository.findByHouse。我已经尝试了一切以确保它在 dbActions 之后返回,但它仍然会发生。
【解决方案2】:

function then 期望提供函数,但您只提供了赋值,并且该赋值同时执行。所以不是

Promise.all(dbActions).then( 
        (promiseResult = Promise.all([
            PetRepository.findByHouse({ houseId: houseId })
        ]))
    )

至少写

Promise.all(dbActions).then( () =>
        (promiseResult = Promise.all([
            PetRepository.findByHouse({ houseId: houseId })
        ]))
    )

但即使是这段代码看起来也很奇怪。为什么要在 Promise.all 中放置一个 Promise,以及您期望在 PromiseResult 中得到什么 - Promise 或 result?

可能是你的意思

Promise.all(dbActions).then( () =>
  PetRepository.findByHouse({ houseId: houseId })
).then(res => { promiseResult = res })

然后在 promiseResult 中你会得到 Pet 实例本身

【讨论】:

  • Promise.all 中只有一个 Promise 的原因是因为我最初的示例有 2 个 Promise,但为了解释起见,我将其省略了。我试试这个,谢谢
【解决方案3】:

我相信我已经找到导致 PetRepository.findByHouse 过早返回的原因。

const save = (houseId, personIds, pets, petsToDelete) => {
    let dbActions = []

    personIds.forEach((personId) => {
        pets.forEach((pet) => {
            pet.ownerId = personId
        })
        dbActions.push(
            PetRepository.deletePets(personId, petsToDelete),
            PetRepository.updatePets(personId, pets),
        )
    })

    return Promise.all(dbActions).then(() => { // this is the correct way to wait for dbActions
                                               // and then return findByHouse(...)
            return PetRepository.findByHouse({ houseId: houseId })
    })
}

【讨论】:

  • 谢谢,我会试一试,如果有效,请告诉您
  • 不,由于某种原因它仍然会发生......如果我查看数据库,一切都会正确更新,但由于某种原因,PetRepository.findByHouse 仍然过早返回。
猜你喜欢
  • 1970-01-01
  • 2012-09-27
  • 2018-10-11
  • 1970-01-01
  • 2016-01-09
  • 2017-08-28
  • 1970-01-01
  • 1970-01-01
  • 2015-08-25
相关资源
最近更新 更多