0

OK, I'm quite new to Javascript and I'm trying to use firebase as the back end for a simple game I'm making.

I have the following very simple javascript code accessing my data:

    var myData = new Firebase("https://theurl.firebaseio.com/Player/results");
    var p1;
    var player1 = myData.child("1");
    player1.on("value", function(snapshot) {
        p1 = snapshot.val();  
        console.log(p1["Name"]+ " " + p1["Draws"]);
    });
    /*
    This line seems to be the problem, how do I assign the result of the query outside the above function? */
    p1["Draws"] += 1;
    player1.update({
        "Draws": p1["Draws"]
    });


The variable p1 doesn't get assigned properly. How can I get around this?

James
  • 3,957
  • 4
  • 37
  • 82

1 Answers1

2

The variable p1 gets assigned perfectly fine. But you're accessing it at a time it hasn't been populated yet.

To see what is happening, let's add a few log statements to your code:

var myData = new Firebase("https://theurl.firebaseio.com/Player/results");
var p1;
var player1 = myData.child("1");
console.log('Before reading from Firebase');
player1.on("value", function(snapshot) {
    p1 = snapshot.val();  
    console.log('Result from Firebase: '+p1["Name"]+ " " + p1["Draws"]);
});
console.log('After reading from Firebase');

p1["Draws"] += 1;
player1.update({
    "Draws": p1["Draws"]
});

When you run this code, you will see that the output is:

Before reading from Firebase

After reading from Firebase

Result from Firebase...

This is probably not the order you expected.

The reason for this is that the data is loaded from Firebase asynchronously. So the line with player1.on("value' starts loading the data from Firebase. But since this may take some time, the browser continues executing the code after the statement. Then when the value from Firebase is available it calls your function with a snapshot of that data.

This type of asynchronous loading is very common in common web programming. To deal with it, you have to invert the logic of your code. Instead of saying: "first I get player1, then I update his draws", think of it as "whenever the value of player1 changes, I do xyz".

You often do this by moving the "then" code into the callback function:

var myData = new Firebase("https://theurl.firebaseio.com/Player/results");
var p1;
var player1 = myData.child("1");
player1.on("value", function(snapshot) {
    p1 = snapshot.val();  
    p1["Draws"] += 1;
    player1.update({
        "Draws": p1["Draws"]
    });
});

For a great explanation on this problem, read Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference

Community
  • 1
  • 1
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Ah! Thank you for a very clear explanation. The code in my question was greatly simplified, so this complicates things for me now, there are going to have to be lots of nested functions to get around the asynchronous issue. – James Feb 15 '16 at 21:42
  • Promises are one way to untangle the nesting: https://www.firebase.com/blog/2016-01-21-keeping-our-promises.html – Frank van Puffelen Feb 15 '16 at 21:46