【问题标题】:Function ends before all asynchronous work completes函数在所有异步工作完成之前结束
【发布时间】:2020-07-15 22:45:49
【问题描述】:

所以我有一个函数可以检查订单是否是 24 小时前,如果是这种情况,我会向用户发送通知,但它似乎并没有完成所有用户的执行,而只是返回某人而其他一些则不是,我认为我在返回承诺时遇到了问题,我不是 javascript 方面的专家,我并不真正了解发生了什么,有时如果一个文档有一个 deviceToken,而不是尝试使用它刚刚完成的所有文档为空,不继续其他用户文档

exports.rememberToFinishOrder = functions.pubsub.schedule('every 3 minutes').onRun(async (context) => {
    var db = admin.firestore();
    const tsToMillis = admin.firestore.Timestamp.now().toMillis()
    const compareDate = new Date(tsToMillis - (24 * 60 * 60 * 1000)) //24 horas
    let snap = await db.collection('orders').where("timestamp","<",new Date(compareDate)).where("status", "in" ,[1,2,4,5,6]).get()
    if(snap.size > 0){
         snap.forEach(async(doc) => {
            const userId = doc.data().uid
            let userSnap = await db.collection('user').doc(userId).get()
                const deviceToken = userSnap.data().deviceToken
                const payload = {
                notification: {
                    title: "¿ Did you received your order ?",
                    body: "We need to know if you have received your order",
                    clickAction: "AppMainActivity"
                },
                data: {
                    ORDER_REMINDER: "ORDER_REMINDER"
                }
            }
            console.log("User: "+doc.data().uid)
            return admin.messaging().sendToDevice(deviceToken,payload) 
        }); 
    } 
});

有时当某些用户的 devicetoken 为空时,它将完成此功能的执行,而不是继续下一个用户,而且它也不会为我的订单集合中的所有用户完成此功能,它会做一些人和一些人不是,这应该是一个原子操作,它会改变该集合中的所有内容,而不仅仅是一些文档

发生了什么?

【问题讨论】:

  • 我在另一个问题中为您提供了模式,您可以在此处应用相同的模式。如果要使用 forEach,则需要使用 Promise.all 等待所有要解决的 Promise,否则,您可以使用 for-of 方法
  • 有consice的方法吗?
  • 什么意思?你的错误是你没有正确处理承诺
  • 你能帮我解决这个问题吗?

标签: javascript firebase google-cloud-firestore google-cloud-functions


【解决方案1】:

就像 andresmijares 所说,您是否没有正确处理承诺。 当您进行多个异步调用时,我建议使用 Promise.all() 函数,该函数将等待所有承诺完成后再继续。

exports.rememberToFinishOrder = functions.pubsub.schedule('every 3 minutes').onRun(async (context) => {
    const db = admin.firestore();
    const messaging = admin.messaging();

    const tsToMillis = admin.firestore.Timestamp.now().toMillis()
    const compareDate = new Date(tsToMillis - (24 * 60 * 60 * 1000)) //24 horas
    
    const snap = await db.collection('orders').where("timestamp","<",new Date(compareDate)).where("status", "in" ,[1,2,4,5,6]).get()
    let allPromises = [];

    if(snap.size > 0){
        snap.forEach((doc) => {
            const userId = doc.data().uid;

            allPromises.push(db.collection('user').doc(userId).get().then(userSnapshot => {
                const userData = userSnapshot.data();
                const deviceToken = userData.deviceToken;
                if (userData && deviceToken) {
                    
                    const payload = {
                        notification: {
                            title: "¿ Did you received your order ?",
                            body: "We need to know if you have received your order",
                            clickAction: "AppMainActivity"
                        },
                        data: {
                            ORDER_REMINDER: "ORDER_REMINDER"
                        }
                    }
                    console.log("User: "+doc.data().uid)
                    return messaging.sendToDevice(deviceToken,payload) 
                } else {
                    return;
                }
            }));
        }); 
    }
    return Promise.all(allPromises);
});

编辑: 在发送通知之前,我添加了一个检查以查看 userData 上是否存在 deviceToken。

【讨论】:

  • 嗨伦科非常感谢你的回答,我马上测试一下
  • 由于我在该集合中有超过 500 个订单,我认为我需要将其作为批处理操作执行,您能帮我更新此代码以在 500 个操作的批处理上运行吗?还是批次仅用于写操作?谢谢
  • 批次仅用于 Cloud Firestore 的设置、更新和删除操作。请参阅the documentation 了解有关批次的更多信息。
猜你喜欢
  • 2021-03-24
  • 2020-04-08
  • 1970-01-01
  • 1970-01-01
  • 2015-09-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多