0

I have a function getHighScores which I want to go into a JSON file and get score objects for a given game, sort them, and return the top amount of them.

This is my (broken) code:

function getHighScores(game, amount) {
    var highScores = null;
    fs.readFile('scores.json', 'utf8', function (error, data) {
        var scoresObj = JSON.parse(data);
        var gameScores = scoresObj.games[game];
        sortedScores = gameScores.sort(compareScoreObjects);
        highScores = sortedScores.slice(0, amount);
    });
    return highScores;
}

console.log(getHighScores('snake', 10));

This is logging null, because highScores cannot be accessed within the scope of the callback function for fs.readFile.

Is there any way to do this while maintaining the logic of my code - where I can simply have getHighScores return the data? If not, how should I be thinking about this problem?

Josh Katofsky
  • 511
  • 6
  • 13

2 Answers2

4

The problem here is you're using readFile, which is an asynchronous method. Meaning by the time this method resolves, highScores is already returned.

Checkout the readFileSync method (https://nodejs.org/api/fs.html#fs_fs_readfilesync_path_options) which is a synchronous version of readFile.

You can then change your code as follows.

function getHighScores(game, amount) {
  var scoresObj = fs.readFileSync('scores.json', 'utf8');
  var parsedScoresObj = JSON.parse(data);
  var gameScores = parsedScoresObj.games[game];
  var sortedScores = gameScores.sort(compareScoreObjects);
  var highScores = sortedScores.slice(0, amount);
  return highScores;
}
Josh Katofsky
  • 511
  • 6
  • 13
Reza Assar
  • 86
  • 3
2

From what I have read, fs.readfile is async. So highScores is returning immediately instead of wating to read the file. You could change the code to be synchronous.

function getHighScores(game, amount) {
var highScores = null;
var data = fs.readFileSync('scores.json', 'utf8')
var scoresObj = JSON.parse(data);
var gameScores = scoresObj.games[game];
sortedScores = gameScores.sort(compareScoreObjects);
highScores = sortedScores.slice(0, amount);
return highScores;
}

console.log(getHighScores('snake', 10));

If you want to keep it asynchronous though then you should check this link

How do I return the response from an asynchronous call?