简体   繁体   English

从 firebase 函数返回数据返回 null

[英]Returning data from firebase functions returns null

I have this code我有这个代码

exports.battle = functions.https.onCall((data, context) => {
    if(context.auth){
        var difficulty = randInt(2,10) / 10
        var user = context.auth["uid"]
        
        var userHP
        var userLevel
        var userDmg 
        var resultUserDmg = []
        var resultUserHp = []

        var monsterHP
        var monsterLevel
        var monsterDmg
        var resultMonsterDmg = []
        var resultMonsterHp = []

        

        var ref = db.ref(`players/${user}`);
        ref.child("hp").once("value", (snapshot) => {
           userHP = snapshot.val()
           monsterHP = userHP * difficulty

           ref.child("level").once("value", (snapshot) => {
                userLevel = snapshot.val()
                monsterLevel = userLevel * difficulty

                console.log("type"+typeof(userHP))
                console.log("value"+userHP)
                

                console.log("type"+typeof(monsterHP))
                console.log("value"+monsterHP)
                console.log("diff "+difficulty)


                while (userHP > 0 && monsterHP > 0){
                    userDmg = randInt(7, 14) * userLevel
                    monsterDmg = randInt(7, 14) * userLevel * difficulty


                    userHP = Math.round((userHP - monsterDmg)*10) /10;
                    console.log("userHP"+(userHP))
                    console.log("monsterDmg"+monsterDmg)
                    resultMonsterDmg.push(Math.round(monsterDmg*10) /10)
                    resultUserHp.push(Math.round(userHP*10)/10)
                    monsterHP = Math.round((monsterHP - userDmg)*10) /10;
                    console.log("userDmg"+userDmg)
                    console.log("monsterHP"+monsterHP)
                    resultUserDmg.push(Math.round(userDmg*10)/10)
                    resultMonsterHp.push(Math.round(monsterHP*10)/10)
                    console.log("----------")
                }

            
                var ref = db.ref(`players/${user}/coins`);
                ref.once("value", function(snapshot) {
                    var coinsNow = parseInt(snapshot.val());
                    const userRef = db.ref(`players/${user}`);
                    userRef.update({
                        'coins' : coinsNow+1
                    })
                });

                var result ={
                    userDmg : resultUserDmg,
                    userHp : resultUserHp,
                    monsterDmg : resultMonsterDmg,
                    monsterHp : resultMonsterHp,
                    monsterLvl : monsterLevel,
                };
                console.log("result is "+resultUserDmg)
                console.log("result is "+resultUserHp)
                console.log("result is "+resultMonsterDmg)
                console.log("result is "+resultMonsterHp)
                console.log("result is "+monsterLevel)
                return result 

            })
        })
    }
    else{
        console.log("User is not logged")
    }

    
})

Simply what this code does is that it calculates the player's life and damage against the monster using a while loop.这段代码所做的只是使用 while 循环计算玩家的生命和对怪物的伤害。 This works correctly.这工作正常。 The problem is when I want to send the data in the result variable to the user for further work.问题是当我想将结果变量中的数据发送给用户以供进一步工作时。 It returns null every time.每次返回null。 Do you know where the error is?你知道错误在哪里吗? The only thing I can think of is that the error would be in the return.我唯一能想到的是错误会在回报中。 Maybe it gets called before the requested data has any value.也许它在请求的数据有任何价值之前被调用。 I don't know.我不知道。 I can't figure it out.我想不通。

But I am sure that the values I want to send to the user are not null but have the values they should have.但我确信我要发送给用户的值不是 null 而是它们应该具有的值。 Here is the log from the firebase console这是来自 firebase 控制台的日志

Firebase console log Firebase 控制台日志

Here is code that i am useing for client returning.这是我用于客户返回的代码。 I always get null here我总是在这里得到 null

var battle = firebase.functions().httpsCallable('battle')
    battle().then(result => {
        console.log(result)
    })

UPDATE: Frank's response was great direction.更新:弗兰克的回应是很好的方向。 But I don't think it's entirely clear.但我不认为这是完全清楚的。 After a longer search, I found a more understandable solution for me here: https://medium.com/@stephane.giron/firebase-cloud-functions-oncall-returned-before-end-of-the-function-2d898d8ff259经过更长时间的搜索,我在这里找到了一个更容易理解的解决方案: https://medium.com/@stephane.giron/firebase-cloud-functions-oncall-returned-before-end-of-the-function-2d898d8ff259

I simply changed this at the beginning of the code ann add this to the end我只是在代码的开头更改了它并将其添加到末尾

exports.battle = functions.https.onCall((data, context) => {
    if(context.auth){
         return new Promise(function(resolve, reject) {
                
                 /* 
                   . . . .                       
                     code 
                   . . . .
                            */

                 reslove(result)
)}

I hope this has helped someone else.我希望这对其他人有所帮助。 I recommend adding .catch to the end of the code for possible errores but I'm not entirely sure so I don't want to possibly confuse我建议将.catch添加到代码的末尾以防止可能的错误,但我不完全确定所以我不想混淆

Results from Promises bubble up to the caller, but only if you actually return them from within your then or catch callbacks. Promises 的结果冒泡到调用者,但前提是您实际上从thencatch回调中返回它们。 So inside every once callback you'll need to ensure that you return the value to the caller.因此,在once回调中,您都需要确保将值return给调用者。

So first up, you're missing a top-level return statement in your top-level Cloud Function, which means that your return result never makes it to the caller.所以首先,您在顶级云 Function 中缺少顶级return语句,这意味着您的return result永远不会到达调用者。

So:所以:

return ref.child("hp").once("value", (snapshot) => {
  ...
})

Next up, you'll need to do the same for ref.child("level").once("value", (snapshot) => { and other individual once calls.接下来,您需要对ref.child("level").once("value", (snapshot) => {和其他单独的once调用执行相同的操作。

Finally, if you have a loop where you perform an asynchronous operation (such as once or update ) for each item in the loop, you can use Promise.all to wait for all of these operations to complete before completing the operation and return a value to the caller.最后,如果你有一个循环,你在其中对循环中的每个项目执行异步操作(例如onceupdate ),你可以使用Promise.all等待所有这些操作完成,然后再完成操作并返回一个值给来电者。

I recommend reading up on Promises here in Using Promises on MDN, in the Firebase documentation on terminating functions: sync, async and promises and by watching Doug's excellent video series linked there.我建议阅读 MDN 上的Using Promises中的 Promises,阅读关于 终止函数的 Firebase 文档:sync、async 和 promises ,并观看链接在此处的 Doug 的优秀视频系列。


Unrelated, but this code is much more complex than needed:不相关,但这段代码比需要的复杂得多:

var ref = db.ref(`players/${user}/coins`);
ref.once("value", function(snapshot) {
    var coinsNow = parseInt(snapshot.val());
    const userRef = db.ref(`players/${user}`);
    userRef.update({
        'coins' : coinsNow+1
    })
});

The Firebase Realtime Database nowadays has a built-in increment operation , which means that you can simplify this to:现在的 Firebase Realtime Database 已经内置了increment操作,这意味着您可以将其简化为:

db.ref(`players/${user}/coins`).set(firebase.database.ServerValue.increment(1));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM