-1

My issue is that my code is assigning champName to a different value inside function in the readfile call. However, after the call is over, champName does not retain that value even though it is declared globally for that function. How do I fix this?

The code below is what I have right now. Previously I tried to have the for loop outside of the function, but then I would get errors about cannot read property 'length' of undefined even though undefined should be champsJson, which was previously defined, meaning that champsJson doesn't get updated outside of that method.

//This function takes in a champId (number) and returns the appropriate 
//string that is associated with that champId
function decipherChamp(champId) {
    //Local variables
    var champName = 'This should never print';
    var champsJson = ''

    //Reads champions.json into rawData
    fs.readFile('./commands/lol/champions.json', 'utf8', function (err, data) {
        if (err)
            throw err;
        champsJson = JSON.parse(data);
        for (let i = 0; i < champsJson.length; i++) {
            if (champsJson[i].championId == champId) {
                champName = champsJson[i].championName;
                console.log("champName inside fn: " + champName)
            }
        }
    });
    console.log("champName before return: " + champName)
    return champName
}    

I've added console.log("champName before return: " + champName) to see what champName is right before printing, and it prints This should never print, the initialized value, instead of the expected result, <The Champion's Name>

Observed output:

Running command lol:currgame. champName before return: This should never print champName inside fn: Brand champName before return: This should never print champName inside fn: Graves champName before return: This should never print champName inside fn: Tristana champName before return: This should never print champName inside fn: Jax champName before return: This should never print champName inside fn: Malzahar champName before return: This should never print champName inside fn: Thresh champName before return: This should never print champName inside fn: Galio champName before return: This should never print champName inside fn: Kai'Sa champName before return: This should never print champName inside fn: Trundle champName before return: This should never print champName inside fn: Kennen

Expected output:

Running command lol:currgame. champName before return: Brand champName inside fn: Brand champName before return: Graves champName inside fn: Graves champName before return: Tristana ...

I also noticed that it prints the champName before the return before the inside of the function result, which makes me believe that it is an error with my understanding of async in node, but I'm not sure.

Maxypoo
  • 33
  • 8

2 Answers2

1

Using fs.readFileSync() is valid, but not necessarily a good solution.

Sync operations in Node (such as file I/O) can be blocking and affect your app in unexpected ways. A better solution would be to use

const { promisify } = require('util');
const asyncReadFile = promisify(fs.readFile);

at the top of your file and change decipherChamp() code to something along these lines:

async function decipherChamp ( champId )

    let champName = `Never see me...`;
    let champData;

    try {
        const file = await asyncReadFile(...);
        champData = JSON.parse(file);
    }
    catch (e) { 
        console.error(e); // error handling - failed to read file
        champName = `FAILED!`; // or whatever when error occurs
    }

    const champ = champData.find(champ => champ.championId == champId);
    if ( champ ) {
        champName = champ.champName;
    }
    console.log(...);
    return champName;
}
Deryck
  • 7,608
  • 2
  • 24
  • 43
0

The solution was to change the method call from fs.readFile to fs.readFileSync.

champsJson = JSON.parse(fs.readFileSync('./commands/lol/champions.json', 'utf8'))

and to move the for loop after that assignment.

Maxypoo
  • 33
  • 8