You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 13:52:52