Too much recursion error in Firebase

2019-05-26 08:46发布

I have a function in my global scope that listens for values on a FB ref.

function updateCredits(userID){

    var userRef = database.ref('users/' + userID);
    userRef.on('value', function(snapshot){        
        var userCredits = snapshot.val().credits;
        console.log(userCredits);
        console.log('account: ' + userID + " has " + userCredits + " credits");
        var updatedCredits = userCredits + ANTE;
        userRef.update({credits: updatedCredits});        
        console.log("now it has " + updatedCredits + ANTE);
    });
}

articlesRef.on('child_added', function(data) {
    var upVoteRef = database.ref('articles/' + data.key + '/upVotes/');
    try {
        var upVotersRef = database.ref('articles/' + data.key + '/upVoters/');
        upVoteRef.on('value', function(childData){
            upVotersRef.on('value', function(voterData){
                var voterKeys = Object.keys(voterData.val());
                for (var i=0; i<voterKeys.length; i++){                
                    upVotersRef.child(voterKeys[i]).on('value', function(voterID){
                        console.log("trying with voter ID " + voterID.val());
                        updateCredits(voterID.val());                    
                    });                
                }
            });
        });
    } catch(err){

        console.log(err.message);

    }

    var downVoteRef = database.ref('articles/' + data.key + '/downVotes/');
    downVoteRef.on('value', function(childData){
        console.log(childData.val());

    });


});

Somehow, when I load the page, this function is apparently called hundreds or thousands of times. I get this logged to the console:

account: HMHZ8Ga3UGhc2wSczHDuFL82FB02 has 1328.6999999997329 credits  app.js:25:9
1328.6999999997329  app.js:24:9
1328.8999999997327  app.js:24:9
account: HMHZ8Ga3UGhc2wSczHDuFL82FB02 has 1328.8999999997327 credits  app.js:25:9
1328.8999999997327  app.js:24:9
account: HMHZ8Ga3UGhc2wSczHDuFL82FB02 has 1328.8999999997327 credits  app.js:25:9
1328.9999999997326  app.js:24:9
account: HMHZ8Ga3UGhc2wSczHDuFL82FB02 has 1328.9999999997326 credits  app.js:25:9
1328.9999999997326  app.js:24:9
account: HMHZ8Ga3UGhc2wSczHDuFL82FB02 has 1328.9999999997326 credits  ...

(As you can see, for some reason the same account is being repeatedly given credits. I want it to only be given credits on an upVote);

It continues with..

now it has 1330.09999999973160.1  app.js:28:9
now it has 1329.99999999973170.1  app.js:28:9
now it has 1329.89999999973180.1  app.js:28:9
now it has 1329.79999999973190.1  app.js:28:9
now it has 1329.6999999997320.1  app.js:28:9

... and finally, the problem:

too much recursion[Learn More]  firebase.js:293:781

I guess the updateCredits function is triggering an event being listened to by the upVoteRef, which in turns calls the updateCredits function and becomes circular. I don't know how to avoid this. Any ideas?

1条回答
干净又极端
2楼-- · 2019-05-26 09:02

Solution

You could do

userRef.once('value').then(function(snapshot){

instead of

userRef.on('value', function(snapshot){  

Explanation

What on('value') does is that it fires once to fetch all the data at that path, and then fires again every time that data on that path changes.

Since you update the data on the same path in the callback with

userRef.update({credits: updatedCredits});

The data on that path changes and the original event (.value on usersRef) fires again, which in turn fires your callback and you again update the value which .... and so on. This is an infinite loop which causes your error.

To avoid this, you can do several things depending on what you are trying to achieve. If you only want to add ANTE when somebody runs

updateCredits(voterID.val()); 

Then you want to read the data at userRef only once and not actively observe that path. Hence, .once instead of .on

See Read data once - Firebase Documentation

查看更多
登录 后发表回答