Firebase云函数为何在异步流程完成前继续执行?
解决Firebase云函数中FCM令牌获取未等待的问题
问题根源
你在使用forEach遍历管理员ID时,传入了异步函数,但forEach本身不支持等待异步操作完成。当代码执行到console.log("tokens.length is ", tokens.length)时,所有获取令牌的异步请求还在后台处理,此时tokens数组仍然是空的,导致后续无法发送通知。
修复方案
替换forEach为支持异步等待的循环方式,确保所有令牌获取完成后再执行后续逻辑。以下两种方案任选其一:
方案一:使用for...of循环(顺序执行)
这种方式会逐个处理管理员的令牌请求,适合对请求顺序有要求的场景:
const tokens: string[] = []; // 替换forEach为for...of,确保等待每个异步操作完成 for (const shopAdmin of shopAdminsArray) { const user = await admin .firestore() .collection("fcm_tokens") .doc(shopAdmin) .get(); console.log("user.data()?.token is ", user.data()?.token); if (user.data()?.token) { tokens.push(user.data()?.token); } }
方案二:使用Promise.all(并行执行,效率更高)
如果管理员数量较多,并行请求能显著提升处理速度:
// 生成所有获取令牌的Promise const tokenPromises = shopAdminsArray.map(async (shopAdmin) => { const user = await admin.firestore().collection("fcm_tokens").doc(shopAdmin).get(); return user.data()?.token; }); // 等待所有Promise完成,过滤掉空令牌 const tokens = (await Promise.all(tokenPromises)).filter(token => token !== undefined) as string[];
完整修改后的代码(以for...of为例)
exports.sendNotifications = functions.firestore .document("messages/{messageId}") .onCreate(async (snapshot) => { // Notification details. let text = snapshot.data().message_body || ""; if (text.length > 100) { text = text.substring(0, 97) + "..."; } const payload = { notification: { title: `הודעה חדשה מ${snapshot.data().name}`, body: text, // icon: // snapshot.data().profilePicUrl || "/images/profile_placeholder.png", // click_action: `https://${process.env.GCLOUD_PROJECT}.firebaseapp.com`, }, }; const shopID = snapshot.data().shop_id; const shopData = await admin .firestore() .collection("shops") .doc(shopID) .get(); const shopAdminsArray = shopData.data()?.admins; console.log("shopAdminsArray is ", shopAdminsArray); // 提前判断管理员数组是否为空 if (!shopAdminsArray || shopAdminsArray.length === 0) { functions.logger.log("No admins found for the shop"); return; } const tokens: string[] = []; for (const shopAdmin of shopAdminsArray) { const user = await admin .firestore() .collection("fcm_tokens") .doc(shopAdmin) .get(); console.log("user.data()?.token is ", user.data()?.token); if (user.data()?.token) { tokens.push(user.data()?.token); } } console.log("tokens.length is ", tokens.length); if (tokens.length > 0) { // Send notifications to all tokens. const response = await admin.messaging().sendToDevice(tokens, payload); await cleanupTokens(response, tokens); functions.logger.log( "Notifications have been sent and tokens cleaned up." ); } });
内容的提问来源于stack exchange,提问作者Tsabary
相关产品推荐
相关产品推荐

