'Unexpected token'在 Nodejs 中递归调用异步函数时



我的应用程序在Firebase Firestore中包含带有嵌套评论的帖子,其结构使得每个带有docID的帖子/评论都有一个子集合postComments。因此,给定的帖子/评论可以有无限数量的嵌套评论。

comments
- docID
postComments
- docID
- docID
- docID
- docID
postComments
- docID
- docID

我目前正在编写一个Firebase云函数,以递归方式查询给定docID的所有文档和子集合文档,并在数组中返回所有这些文档。我的计划是定义getChildComments异步函数,该函数接收docID并返回该文档的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。从这一行中删除wait修复了构建问题,但递归调用没有完成。

我应该如何解决我的问题?或者有更好的方法来查询所有嵌套文档吗?

这是因为您在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数组的填充。

要正确修复此问题,除了使用Promise.all等待检索每个注释(及其子注释(之外,还需要在commentsQuerySnap.docs数组中使用.map()

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);
}
})
)
);

虽然上面的块可以工作,但注释数组可能与您预期的不一样。若必须维护获取的注释的顺序,以便它们与查询的顺序相同,那个么应该为每个文档返回构建的注释数组,然后在检索完所有注释后将其展开。

// 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();

最新更新