为什么异步 firebase 获取不起作用?(NODE JS)
构建 NodeJS REST API。 尝试从 FireBase 集合发送加载数据,然后将其发送给用户(作为 API 响应)。 问题似乎在于它没有等待 FireBase 获取解析,而是返回没有集合数据的响应。(尝试使用 ASYNC-AWAIT,但不起作用)
exports.getChatMessages = async (req, res, next) => {
const chatId = req.params.chatId
const getChatData = () => {
db
.collection('chats')
.doc(chatId)
.collection('messages')
.orderBy('timeStamp', 'asc')
.onSnapshot((snapshot) => {
snapshot.docs.forEach(msg => {
console.log(msg.data().messageContent)
return {
authorID: msg.data().authorID,
messageContent: msg.data().messageContent,
timeStamp: msg.data().timeStamp,
}
})
})
}
try {
const chatData = await getChatData()
console.log(chatData)
res.status(200).json({
message: 'Chat Has Found',
chatData: chatData
})
} catch (err) {
if (!err.statusCode) {
err.statusCode(500)
}
next(err)
}
}
如您所见,我使用了 2 个 console.log 来实现问题所在,终端日志如下所示:
- [](来自 console.logs(chatData))
- 所有消息(来自 console.log(msg.data().messageContent))
有没有办法阻止代码,直到真正获取 FireBase 数据?
如果我理解正确的话,您想要发回
messages
子集合中存在的所有文档的数组。以下应该可以解决问题。
exports.getChatMessages = async (req, res, next) => {
const chatId = req.params.chatId;
const collectionRef = db
.collection('chats')
.doc(chatId)
.collection('messages')
.orderBy('timeStamp', 'asc');
try {
const chatsQuerySnapshot = await collectionRef.get();
const chatData = [];
chatsQuerySnapshot.forEach((msg) => {
console.log(msg.data().messageContent);
chatData.push({
authorID: msg.data().authorID,
messageContent: msg.data().messageContent,
timeStamp: msg.data().timeStamp,
});
});
console.log(chatData);
res.status(200).json({
message: 'Chat Has Found',
chatData: chatData,
});
} catch (err) {
if (!err.statusCode) {
err.statusCode(500);
}
next(err);
}
};
异步
get()
方法返回一个
QuerySnapshot
,您可以在其上调用
forEach()
来枚举
QuerySnapshot
中的所有文档。
您只能
await
一个 Promise。目前,
getChatData()
不返回 Promise,因此等待它是没有意义的。您正在尝试等待一个固定值,因此它会立即解析并跳转到下一行。
console.log(chatData)
发生。然后,稍后,您的
(snapshot) =>
回调会发生,但为时已晚。
const getChatData = () => new Promise(resolve => { // Return a Promise, so it can be awaited
db.collection('chats')
.doc(chatId)
.collection('messages')
.orderBy('timeStamp', 'asc')
.onSnapshot(resolve) // Equivalent to .onSnapshot((snapshot) => resolve(snapshot))
})
const snapshot = await getChatData();
console.log(snapshot)
// Put your transform logic out of the function that calls the DB. A function should only do one thing if possible : call or transform, not both.
const chatData = snapshot.map(msg => ({
authorID: msg.data().authorID,
messageContent: msg.data().messageContent,
timeStamp: msg.data().timeStamp,
}));
res.status(200).json({
message: 'Chat Has Found',
chatData
})
现在,
getChatData
是这样的(简短版本):
const getChatData = () => {
db
.collection('chats')
.doc(chatId)
.collection('messages')
.orderBy('timeStamp', 'asc')
.onSnapshot((snapshot) => {}) // some things inside
}
这意味着
getChatData
函数
调用
一些数据库查询,然后返回
void
(无)。我敢打赌你会想要
返回数据库调用
(希望它是一个 Promise),这样你的
await
就能为你做一些工作。类似这样的代码:
const getChatData = async () =>
db
.collection('chats')
// ...
这与
const getChatData = async() => 相同{ return db... }
更新
:现在我再次查看了文档,我发现您使用了
onSnapshot
,它用于
更新
并且可以多次触发。第一次调用实际上发出了一个请求,但随后继续监听这些更新。由于这看起来像是一个常规的请求-响应,并且您希望它只发生一次 - 使用
.get()
docs
而不是
.onSnapshot()
。否则那些监听器会留在那里并造成麻烦。
.get()
返回一个 Promise,因此我上面提到的示例修复将完美运行,您无需更改代码的其他部分。