Swift 执行异步云函数时出现问题

Swift 执行异步云函数时出现问题,swift,firebase,firebase-cloud-messaging,google-cloud-functions,Swift,Firebase,Firebase Cloud Messaging,Google Cloud Functions,我的数据库看起来像这样 我的云功能是 // The Cloud Functions for Firebase SDK to create Cloud Functions and setup triggers. const functions = require('firebase-functions'); // The Firebase Admin SDK to access the Firebase Realtime Database. const admin = require('fire

我的数据库看起来像这样

我的云功能是

// The Cloud Functions for Firebase SDK to create Cloud Functions and setup triggers.
const functions = require('firebase-functions');

// The Firebase Admin SDK to access the Firebase Realtime Database.
const admin = require('firebase-admin');
admin.initializeApp();

exports.userGotNewMessage = functions
.region(`europe-west1`)
.database
.ref(`user-messages/{userId}/{senderId}/{messageId}`)
.onCreate((snap, context) => {
  var userId = context.params.userId
  console.log(`Step 1  ${userId}`)
  var text = snap.val().text
  var toId = snap.val().toId
  var numberOfUnreadMessages = 0
  var db = admin.database()

  if (userId === toId) {
    console.log(`Step 2 ${userId}`)
  var unreadMessagesRef = db.ref(`unread-messages/${userId}`)
  unreadMessagesRef.on("value", (snap) => {
    snap.forEach((childNode) => {
      var nodeNumber = childNode.val().numberOfUnreadMessages
      numberOfUnreadMessages = numberOfUnreadMessages + nodeNumber
    })
    return console.log(`Found ${numberOfUnreadMessages} unread messages for ${userId}`)
  });

  console.log(`Step 3 ${userId}`)
  var token = 'dxfAkmce.....my testing device'
  console.log(text)
  var message = {
    "token": String(token),
    "data": {
      "count": `${numberOfUnreadMessages}`
    }
  }

  admin.messaging().send(message)
  .then((response) => {
    console.log(`Step 4 ${userId}`)
    // Response is a message ID string.
    return console.log('Successfully sent message:', response);
    // detailed information about result if send succeded but something went wrong
    // console.log(response.results[0].error);
  })
  .catch((error) => {
    return console.log('Error sending message:', error);
  });
  }
  console.log(`Step 5 ${userId}`)
  return null
});
使用这个函数我会有奇怪的行为。未读消息的数量在消息发送后计算,还有更多,例如,在开始之后,我从现在获得了有关已计算未读消息的消息,在数据库中根本没有16条消息 控制台中类似这样的东西

下午3:05:23.627 userGotNewMessage成功发送消息: 项目/chatapp-2e320/messages/1544015123460374

下午3:05:23.626用户获取新消息步骤4 VobaLy7AKMeYnGv7OgIokaeQ5UG2

下午3:05:23.340 userGotNewMessage函数执行耗时9毫秒, 完成状态:“确定”

下午3:05:23.334用户获取新消息步骤5 nx9XfqgIqyS8PdZ8PzLQ9sEyKoV2

下午3:05:23.333用户获取新消息步骤1 nx9XfqgIqyS8PdZ8PzLQ9sEyKoV2

3:05:23.331 PM userGotNewMessage函数执行已开始

下午3:05:23.325 userGotNewMessage函数执行耗时151毫秒, 完成状态:“确定”

下午3:05:23.317用户获取新消息步骤5 VobaLy7AKMeYnGv7OgIokaeQ5UG2

下午3:05:23.317 userGotNewMessage再次问候

下午3:05:23.317用户获取新消息步骤3 VobaLy7AKMeYnGv7OgIokaeQ5UG2

下午3:05:23.317 userGotNewMessage为找到1封未读邮件 VobaLy7AKMeYnGv7OgIokaeQ5UG2

下午3:05:23.234用户获取新消息步骤2 VobaLy7AKMeYnGv7OgIokaeQ5UG2

下午3:05:23.234用户获取新消息步骤1 VobaLy7AKMeYnGv7OgIokaeQ5UG2

下午3:05:23.182 userGotNewMessage为找到16条未读邮件 VobaLy7AKMeYnGv7OgIokaeQ5UG2

3:05:23.175 PM userGotNewMessage函数执行已开始


我知道这是由异步工作引起的,但我不能自己解决它,因为我是一个完全的初学者。请帮我修复这个错误

您应该返回异步响应

return admin.messaging().send(message)
  .then((response) => {
    console.log(`Step 4 ${userId}`)
    // Response is a message ID string.
    return console.log('Successfully sent message:', response);
    // detailed information about result if send succeded but something went wrong
    // console.log(response.results[0].error);
  })
  .catch((error) => {
    return console.log('Error sending message:', error);
  });
  }
  console.log(`Step 5 ${userId}`)

正如@rijin在回答中所说的,您应该返回异步send方法返回的承诺。但是,同样重要的是,您不应该在Cloud函数的末尾返回null

通过返回null(这将发生在send返回的承诺解析之前),您向云函数指示工作已经完成。因此,换句话说,在异步作业完成之前,云函数停止执行

此外,在生命周期相对较短的云函数中使用on侦听器实际上是不够的。你最好使用这种方法

最后,您显然在云功能中实现了两个不同的业务逻辑部分,一部分用于报告大量未读消息,另一部分用于发送消息。您应该在两个不同的云函数中实现这一点,或者链接异步方法返回的不同承诺,即once和send方法

因此,对于消息发送部分,执行以下操作应该有效:

exports.userGotNewMessage = functions
.region(`europe-west1`)
.database
.ref(`user-messages/{userId}/{senderId}/{messageId}`)
.onCreate((snap, context) => {
  var userId = context.params.userId
  console.log(`Step 1  ${userId}`)
  var text = snap.val().text
  var toId = snap.val().toId
  var numberOfUnreadMessages = 0
  var db = admin.database()


  console.log(`Step 3 ${userId}`)
  var token = 'dxfAkmce.....my testing device'
  console.log(text)
  var message = {
    "token": String(token),
    "data": {
      "count": `${numberOfUnreadMessages}`
    }
  }

  return admin.messaging().send(message);

});
如果您想将send和once方法链接到一个云函数中,您可以按照以下方式进行操作:

return admin.messaging().send(message)
.then(messageID => {
    if (userId === toId) {
        var unreadMessagesRef = db.ref(`unread-messages/${userId}`);
        return unreadMessagesRef.once('value')
            .then(snap => {
                snap.forEach(childNode => {
                    var nodeNumber = childNode.val().numberOfUnreadMessages;
                    numberOfUnreadMessages = numberOfUnreadMessages + nodeNumber;
                });
                console.log(`Found ${numberOfUnreadMessages} unread messages for ${userId}`);
                return null;
            });
    } else {
        return null;
    }
});

你刚才不是抄了我的代码吗?我不明白你的意思,只是在异步块中添加一个返回语句。谢谢你的解释。在您的示例中,未读邮件的计数是在发送邮件后执行的,但我希望未读邮件的数量包含在邮件的数据中。是否可以使用.then on once方法并发送.然后?