承诺解决后如何调用函数?

How to call a function after the promise has been resolved?

以下代码适用于我的 FCM 函数,在构建要发送的有效负载之前,我正在听 firstore 获取令牌。每次发送时,系统都会记录令牌为空。发送fcm时如何确保它不为空?

let functions = require('firebase-functions');

let admin = require('firebase-admin');

admin.initializeApp(functions.config().firebase);

exports.sendNotification =functions.firestore.document('chatrooms/{chatRoomId}/messages/{messageId}')
.onWrite((snap, context) => {

    let message = snap.after.data().messageBody;
    let messageSender = snap.after.data().senderName;
    let messageUserId = snap.after.data().userId;
    let chatRoomId = context.params.chatRoomId;

    let tokens = [];
    let chatRoomRef = admin.firestore().collection("chatrooms").doc(chatRoomId);

    return admin.firestore().runTransaction(t => {
        return t.get(chatRoomRef)
            .then(chatroom => {
                let usersArray = chatroom.data().chatMembers;
                usersArray.forEach(user_id => {
                    let userIdRef = admin.firestore().collection("tokens").doc(user_id);
                    return t.get(userIdRef).then(doc => {
                        if (doc.exists) {
                            let user_token = doc.data().token;
                            functions.logger.log('token: ', token);
                            tokens.push(user_token);
                        }
                    }).catch(err => {
                        functions.logger.error(err);
                    })
                });
            });
    }).then(() => {
        //The transaction has run successfully, we expect tokens array to not be empty
        functions.logger.log("Construction the notification message.");
        const payload = {

            data: {
                data_type: "data_type_chat_message",
                title: "Tuchat",
                message: message,
                sender_id: messageUserId,
                sender_name: messageSender,
                chatRoom_id: chatRoomId
            }
        };
        const options = {
            priority: "high",
            timeToLive: 60 * 60 * 24
        };

        return admin.messaging().sendToDevice(tokens, payload).catch(err => {
            functions.logger.error(err);
        });
    }).catch(err => {
        functions.logger.error('Transaction error: ', err);
    })
});

同样在尝试交易之前它返回空令牌。

问题在于您在 forEach 循环中处理承诺的方式。循环不会等待其内部代码解析承诺。目前它只是尽可能快地遍历每个用户 ID,而不是等待查询在其中完成。这意味着代码将在 tokens 可以填充之前继续。

您应该改为收集循环内的每个承诺,并使用 Promise.all() 等待整个批处理,然后 return 来自其中的承诺指示所有工作何时完成。这将确保 tokens 在执行链中的下一个 then 之前包含您想要的所有内容。

代码的一般形式是这样的:

.then(() => {
    const promises = []
    collection.forEach(item => {
        const promise = doSomeWork()
        promises.push(promise)
    })
    return Promise.all(promises)
})
.then(() => {
    // this will continue only after all promises are resolved
})

另请参阅: