我正在使用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 })
})
}