'Unexpected token' 在 Nodejs 中递归调用异步函数时
'Unexpected token' when recursively calling async function in Nodejs
我的应用包含在 Firebase Firestore 中嵌套评论的帖子,其结构使得每个 post/comment 和 docID
都有一个子集合 postComments
。因此,给定的 post/comment 可以有无限数量的嵌套评论。
comments
- docID
postComments
- docID
- docID
- docID
- docID
postComments
- docID
- docID
我目前正在编写一个 Firebase 云函数来递归查询给定 docID
和 return 数组中所有这些文档的所有文档和子集合文档。我的计划是定义 getChildComments
异步函数,该函数接收 docID
和 return 文档的 postComments
子集合中的所有文档。然后我会递归调用 getChildComments
直到我在一个线程中构建了一个包含所有嵌套注释的数组。
exports.loadWholeCommentThread = functions.https.onCall(async (data, context) => {
let comments = await getChildComments(data.rootID);
return comments;
});
async function getChildComments(docID) {
try {
const db = admin.firestore();
const commentsRef = db.collection('comments').doc(docID).collection('postComments');
var comments = [];
const commentsQuerySnap = await commentsRef.get();
commentsQuerySnap.forEach((comment) => {
let commentData = comment.data();
comments.push(commentData);
if (commentData.commentCount > 0) {
let childComments = await getChildComments(commentData.commentID);
comments.concat(childComments);
}
});
return comments;
} catch (error) {
functions.logger.log(error);
throw new functions.https.HttpsError('unknown', 'ERROR0', { message: error.message } )
}
}
不幸的是,当我尝试部署我的代码时,我在 getChildComments
中递归调用 getChildComments
的行中收到错误 Parsing error. Unexpected token getChildComments
。从此行中删除 await 修复了构建问题,但递归调用没有完成。
我该如何解决我的问题?或者有没有更好的方法查询所有嵌套文档?
这是因为您在 async
函数之外使用了 await
(注意它在箭头函数内部!)。
const comments = [];
const commentsQuerySnap = await commentsRef.get();
commentsQuerySnap.forEach((comment) => {
let commentData = comment.data();
comments.push(commentData);
if (commentData.commentCount > 0) {
let childComments = await getChildComments(commentData.commentID); // the keyword "await" here is invalid
comments = comments.concat(childComments);
}
});
但是您不能只将 async
添加到此箭头函数,因为这样您的代码将无法正确等待 comments
数组被填充。
要正确解决此问题,您需要在 commentsQuerySnap.docs
数组上使用 .map()
,此外还要使用 Promise.all
等待检索每个评论(及其子评论)。
const comments = [];
const commentsQuerySnap = await commentsRef.get();
await Promise.all(
commentsQuerySnap.docs.map(
async (comment) => {
let commentData = comment.data();
comments.push(commentData);
if (commentData.commentCount > 0) {
let childComments = await getChildComments(commentData.commentID);
comments = comments.concat(childComments);
}
})
)
);
虽然上面的块有效,但评论数组可能与您预期的顺序不一致。如果您必须维护获取的评论的顺序,以便它们与查询的顺序相同,您应该 return 为每个文档构建评论数组,然后在它们全部被检索后展平它们。
// removed const comments = []; here
const commentsQuerySnap = await commentsRef.get();
const arrayOfCommentThreads = await Promise.all(
commentsQuerySnap.docs.map(
async (comment) => {
let commentData = comment.data();
const commentThread = [commentData];
if (commentData.commentCount > 0) {
let childComments = await getChildComments(commentData.commentID);
commentThread = commentThread.concat(childComments);
}
return commentThread;
})
)
);
const comments = arrayOfCommentThreads.flat();
就个人而言,我更喜欢扩展运算符而不是像这样使用 .concat
:
const commentsQuerySnap = await commentsRef.get();
const arrayOfCommentThreads = await Promise.all(
commentsQuerySnap.docs.map(
async (comment) => {
const commentData = comment.data();
if (commentData.commentCount === 0) {
return [commentData];
}
const childComments = await getChildComments(commentData.commentID);
return [commentData, ...childComments];
})
)
);
const comments = arrayOfCommentThreads.flat();
我的应用包含在 Firebase Firestore 中嵌套评论的帖子,其结构使得每个 post/comment 和 docID
都有一个子集合 postComments
。因此,给定的 post/comment 可以有无限数量的嵌套评论。
comments
- docID
postComments
- docID
- docID
- docID
- docID
postComments
- docID
- docID
我目前正在编写一个 Firebase 云函数来递归查询给定 docID
和 return 数组中所有这些文档的所有文档和子集合文档。我的计划是定义 getChildComments
异步函数,该函数接收 docID
和 return 文档的 postComments
子集合中的所有文档。然后我会递归调用 getChildComments
直到我在一个线程中构建了一个包含所有嵌套注释的数组。
exports.loadWholeCommentThread = functions.https.onCall(async (data, context) => {
let comments = await getChildComments(data.rootID);
return comments;
});
async function getChildComments(docID) {
try {
const db = admin.firestore();
const commentsRef = db.collection('comments').doc(docID).collection('postComments');
var comments = [];
const commentsQuerySnap = await commentsRef.get();
commentsQuerySnap.forEach((comment) => {
let commentData = comment.data();
comments.push(commentData);
if (commentData.commentCount > 0) {
let childComments = await getChildComments(commentData.commentID);
comments.concat(childComments);
}
});
return comments;
} catch (error) {
functions.logger.log(error);
throw new functions.https.HttpsError('unknown', 'ERROR0', { message: error.message } )
}
}
不幸的是,当我尝试部署我的代码时,我在 getChildComments
中递归调用 getChildComments
的行中收到错误 Parsing error. Unexpected token getChildComments
。从此行中删除 await 修复了构建问题,但递归调用没有完成。
我该如何解决我的问题?或者有没有更好的方法查询所有嵌套文档?
这是因为您在 async
函数之外使用了 await
(注意它在箭头函数内部!)。
const comments = [];
const commentsQuerySnap = await commentsRef.get();
commentsQuerySnap.forEach((comment) => {
let commentData = comment.data();
comments.push(commentData);
if (commentData.commentCount > 0) {
let childComments = await getChildComments(commentData.commentID); // the keyword "await" here is invalid
comments = comments.concat(childComments);
}
});
但是您不能只将 async
添加到此箭头函数,因为这样您的代码将无法正确等待 comments
数组被填充。
要正确解决此问题,您需要在 commentsQuerySnap.docs
数组上使用 .map()
,此外还要使用 Promise.all
等待检索每个评论(及其子评论)。
const comments = [];
const commentsQuerySnap = await commentsRef.get();
await Promise.all(
commentsQuerySnap.docs.map(
async (comment) => {
let commentData = comment.data();
comments.push(commentData);
if (commentData.commentCount > 0) {
let childComments = await getChildComments(commentData.commentID);
comments = comments.concat(childComments);
}
})
)
);
虽然上面的块有效,但评论数组可能与您预期的顺序不一致。如果您必须维护获取的评论的顺序,以便它们与查询的顺序相同,您应该 return 为每个文档构建评论数组,然后在它们全部被检索后展平它们。
// removed const comments = []; here
const commentsQuerySnap = await commentsRef.get();
const arrayOfCommentThreads = await Promise.all(
commentsQuerySnap.docs.map(
async (comment) => {
let commentData = comment.data();
const commentThread = [commentData];
if (commentData.commentCount > 0) {
let childComments = await getChildComments(commentData.commentID);
commentThread = commentThread.concat(childComments);
}
return commentThread;
})
)
);
const comments = arrayOfCommentThreads.flat();
就个人而言,我更喜欢扩展运算符而不是像这样使用 .concat
:
const commentsQuerySnap = await commentsRef.get();
const arrayOfCommentThreads = await Promise.all(
commentsQuerySnap.docs.map(
async (comment) => {
const commentData = comment.data();
if (commentData.commentCount === 0) {
return [commentData];
}
const childComments = await getChildComments(commentData.commentID);
return [commentData, ...childComments];
})
)
);
const comments = arrayOfCommentThreads.flat();