代码之家  ›  专栏  ›  技术社区  ›  Tristan

为什么这个firebase可调用函数不返回一个值?

  •  2
  • Tristan  · 技术社区  · 7 年前

    我有一个可调用函数,它应该返回一个值,但唯一返回的是空值。下面是函数的当前版本。我也试过在第一个承诺(最初的 once 呼叫),然后在另一个 then 返回guid。在这种情况下,它实际上返回了数据,但它立即返回,并且guid为空。

    如何完成我的目标并返回guid?我不知道什么时候调用函数,是否要使用我生成的新GUID,或者数据库中已经存在的GUID。

    这里有一个类似的问题: Receiving returned data from firebase callable functions 但在这种情况下,这是因为他从未从函数返回过一个承诺。我将在所有代码路径上返回一个承诺。 除非我必须从 一旦 打电话? 在这种情况下,当我还不知道GUID时,如何返回它?

    我还试图在几个地方抛出一个错误,该错误会显示在函数的日志中,但不会发送到调用该函数的客户机。

    我将从下面的例子中去掉: https://firebase.google.com/docs/functions/callable

    对不起,密码炸弹。

    调用函数:

    var newGame = firebase.functions().httpsCallable('findCreateGame');
            newGame({}).then(function(result) {
                // Read result of the Cloud Function.
                //var sGameID = result.data.guid;
                console.log(result);
            }).catch(function(error) {
                console.log(error);
            });
    

    功能:

    exports.findCreateGame = functions.https.onCall((data, context) => {
        console.log("findCurrentGame Called.")
        /**
        * WHAT NEEDS DONE
        *
        *
        * Pull in user's information
        * Determine their win/loss ratio and search for a game using transactions in either low medium or high queue
        * If there are no open games in their bracket, search the one above, then below
        * If no open games anywhere, create a new game in their bracket
        * If an open game is found, write the UID to the game and add the game's ID to the user's profile
        *
        */
    
        var uid = context.auth.uid;
        var section = "";
        var sUsername = "";
        var sProfilePic = "";
        var currentGames = null;
        var sGUID = "";
    
        //Get the user's info
        var userref = admin.database().ref('users/' + uid);
        userref.once("value", function(data) {
            var ratio = 0;
            var wins = parseInt(data.val().wins);
            var losses = parseInt(data.val().losses);
            var lives = parseInt(data.val().lives);
    
            if (lives < 1){
                //This user is out of lives, should not have been able to get here
                //Throw an exception so that we can see why it failed
                throw new functions.https.HttpsError('permission-denied', 'You do not have enough lives to start a new game.');
            }
            sUsername = data.val().username;
            sProfilePic = data.val().profilepicture;
    
            //Handle if they have no losses
            if (losses == 0){
                ratio = 100;
            } else {
                ratio = (wins / losses) * 100;
            }
    
            //If they have played less than 5 games, put them in noob tier
            if (wins + losses < 5){
                ratio = 0;
            }
    
            if (ratio <= 33){
                section = "noob";
            } else if (ratio > 33 && ratio <= 66){
                section = "average";
            } else {
                section = "expert";
            }
        }).then(() => {
            //Get all of the games this user is currently in
            admin.database().ref('games').orderByChild(uid).once('value', function(data) {
                currentGames = data.val();
            }).then(() => {
    
                //Generate a new GUID in case we need to set up a new game
                sGUID = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
                    var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
                    return v.toString(16);
                });
    
    
    
                var queueref = admin.database().ref('gamequeue/' + section);
                queueref.transaction(function(currentGUID) {
    
                    if (currentGUID == null){
                        //Write our GUID in the queue
                        return sGUID;
                    } else {
                        //Get the id of the game we just got
                        sGUID = currentGUID
    
                        return null;
                    }
                }).then((res) => {
    
                    if (res.snapshot.val() != null){
                        //This means we are creating the game lobby
    
                        //Generate a new answer
                        var newAnswer = "";
                        while (newAnswer.length < 4){
                            var temp = Math.floor(Math.random() * 9) + 1;
    
                            temp = temp.toString();
    
                            if (!newAnswer.includes(temp)){
                                newAnswer += temp;
                            }
                        }
    
                        var obj = {username: sUsername, score: 0, profilepicture: sProfilePic};
    
                        return admin.database().ref('games/' + sGUID).set({id: sGUID, requestor: uid, [uid]: obj, answer: newAnswer, turn: uid, status: 'pending'}).then(() => {
                            return {guid: sGUID};
                        });
                    } else {
                        //We found a game to join
    
                        //If we are in a duplicate request situation, make sure the GUID is a string
                        if (typeof(sGUID) != 'string'){
                            sGUID = Object.keys(sGUID)[0];
                        }
    
                        //Make sure we didn't find our own game request
                        if (currentGames[sGUID] != null){
                            //Add this GUID back to the queue, we shouldn't have removed it
                            return admin.database().ref('gamequeue/' + section + '/' + sGUID).set('');
    
                            //Throw an exception that says you can only have one open game at a time
                            throw new functions.https.HttpsError('already-exists', 'We are still finding a match for your last request. You are only allowed one open request at a time.');
    
                        } else {
                            //Get the current game info
                            admin.database().ref('games/' + sGUID).once('value', function(data) {
                                var sRequestor = data.val().requestor;
                                var sOpponentUsername = data.val()[sRequestor].username;
                                var sOpponentProfilePic = data.val()[sRequestor].profilepicture;
    
                                //Write all of our info to the game
                                return admin.database().ref('games/' + sGUID).update({[sRequestor]: {opponentusername: sUsername, opponentprofilepicture: sProfilePic}, [uid]: {username: sUsername, score: 0, opponentusername: sOpponentUsername, opponentprofilepicture: sOpponentProfilePic}, status: 'active'}).then(() => {
                                    return {guid: sGUID};
                                });
                            });
                        }
                    }
                });
            });
        })
    });
    
    1 回复  |  直到 7 年前
        1
  •  2
  •   Bob Snyder    7 年前

    这个 documentation for callable functions 解释:

    要在异步操作之后返回数据,请返回一个承诺。这个 承诺返回的数据将被发送回客户。

    您有许多必须链接在一起的异步操作。一 return 需要添加到每个语句中(如图所示):

    return userref.once("value", function(data) {...
    
    return admin.database().ref('games').orderByChild(uid).once('value', function(data) {...
    
    return queueref.transaction(function(currentGUID) {...
    
    return admin.database().ref('games/' + sGUID).once('value', function(data) {...