Nodejs express promise.all().then() 不是同步的



我正在使用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有时会在循环中的所有dbActions执行/完成之前返回数据。

我以为将它们添加到数组并在循环外的 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 }

您正在使用 thenables(回调(来解决此问题。使用 async/await 会更容易。为了能够等待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将包含一个 promise,因此为了获得该值,您必须await它(内联(或then它(回调(

函数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 中放了一个承诺,你期望在 promiseResult 中得到什么 - 承诺或结果?

也许是你的意思

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

那么在承诺结果中,你会得到宠物实例本身

我相信我已经找到了导致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 })
})
}

最新更新