我有一个由http请求触发的云功能,它打算执行以下操作:
因此我需要等待(2)和(3)循环的东西然后执行批处理操作。
下面是我目前的代码,当我在本地测试函数时,它正在工作。但是我无法将其部署到Firebase,因为它承诺会出现错误,例如"然后必须返回一个承诺"和#34;避免嵌套承诺"。
exports.finishEvents = functions.https.onRequest((req, res) => {
const eventsRef = admin.firestore().collection('events');
var currentTime = new Date().getTime();
var currentTimeMinus1h = currentTime - 3600000;
console.log('----- finishEvents started -----')
const queryRef = eventsRef.where('finished', '==', false).where('date', '<=', new Date(currentTimeMinus1h)).get().then(function(querySnapshot){
if (querySnapshot.size > 0) {
querySnapshot.forEach(function(doc) {
var owner_id = doc.data().owner_id;
var event_id = doc.id;
console.log(owner_id, event_id);
var userEventOwnerGoingRef = admin.firestore().collection("user_events").doc(owner_id).collection('going').doc(event_id);
userEventOwnerGoingRef.get().then(doc2 => {
if (!doc2.exists) {
console.log('No such document!');
} else {
console.log('Document data:', doc2.data());
var goingIds = doc.data().going_ids;
console.log('GOING IDS', goingIds);
var batch = admin.firestore().batch();
for (var userId in goingIds) {
if (goingIds.hasOwnProperty(userId)) {
console.log(userId + " -> " + goingIds[userId]);
var eventRef = admin.firestore().collection("events").doc(event_id);
var userEventGoingRef = admin.firestore().collection("user_events").doc(userId).collection('going').doc(doc2.id);
var userEventAttendedRef = admin.firestore().collection("user_events").doc(userId).collection('attended').doc(doc2.id);
batch.set(userEventAttendedRef, doc2.data());
batch.delete(userEventGoingRef)
if (userId == doc2.data().owner_id) batch.update(eventRef, {finished: true});
}
}
batch.commit().then(function () {
return res.status(200).send("Done.");
});
}
})
.catch(err => {
console.log('Error getting userEventOwnerGoingRef', err);
return res.status(200).send("Finished.");
});
});
} else {
console.log("No events found");
return res.status(200).send("Finished.");
}
})
.catch(err => {
console.log('Error getting events', err);
return res.status(200).send("Finished.");
});
});
当我在本地测试时,即使作业已完成,我也会收到错误消息
UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Can't set headers after they are sent.
我可以看到我正在为原始查询的每个文档发送结果,我只需要发送一次结果来完成云功能。
我想我需要返回承诺,然后在完成步骤(2)和(3)之后执行我的批处理事务。然而,这是我第一次使用JavaScript,我正在努力解决这个问题。任何帮助将不胜感激。
答案 0 :(得分:4)
当您的HTTPS函数发送了响应但忘记返回在达到超时限制之前解析的承诺时,会遇到Unhandled promise rejection
错误。这意味着您不会在HTTPS函数中返回所有承诺。您的代码应如下所示:
exports.finishEvents = functions.https.onRequest((req, res) => {
const eventsRef = admin.firestore().collection('events')
const currentTime = new Date().getTime()
const currentTimeMinus1h = currentTime - 3600000
console.log('----- finishEvents started -----')
const queryRef = eventsRef
.where('finished', '==', false)
.where('date', '<=', new Date(currentTimeMinus1h))
return queryRef.get().then((querySnapshot) => {
// Use Promise.all with snapshot.docs.map to combine+return Promise context
return Promise.all(querySnapshot.docs.map((doc) => {
const owner_id = doc.get('owner_id')
const event_id = doc.id
console.log(owner_id, event_id)
const userEventOwnerGoingRef = admin.firestore()
.collection("user_events").doc(owner_id)
.collection('going').doc(event_id)
return userEventOwnerGoingRef.get().then((doc2) => {
if (!doc2.exists) {
console.log('No such document!')
return
} else {
console.log('Document data:', doc2.data())
const goingIds = doc.get('going_ids')
console.log('GOING IDS', goingIds)
const batch = admin.firestore().batch()
for (const userId in goingIds) {
if (goingIds.hasOwnProperty(userId)) {
console.log(userId + " -> " + goingIds[userId])
const eventRef = admin.firestore().collection("events").doc(event_id)
const userEventGoingRef = admin.firestore()
.collection("user_events").doc(userId).collection('going').doc(doc2.id)
const userEventAttendedRef = admin.firestore()
.collection("user_events").doc(userId).collection('attended').doc(doc2.id)
batch.set(userEventAttendedRef, doc2.data())
batch.delete(userEventGoingRef)
if (userId == doc2.get('owner_id')) {
batch.update(eventRef, {finished: true})
}
}
}
return batch.commit()
}
})
}))
})
.then(() => {
return res.status(200).send('Done.')
})
.catch((err) => {
console.error(err)
return res.status(200).send('Finished.')
})
})
从这一点来看,重要的是不要束缚你的任何承诺。无论是通过将它们添加到数组还是等待它们全部解析/拒绝,或者通过从它们的范围/函数返回它们,始终保持它们的句柄。我希望这会有所帮助。