Simple nodejs callback example with fs.readFile

30,195

Solution 1

You have several issues going on and I'll try to outline them all as best as possible

Problem 1: Variable scope

var fs = require('fs');
var pathToFile = process.argv[2];

function counter(callback) {
  var buffer = fs.readFile(pathToFile, function (err, data) { 
    // Both of the following variables are scoped to the callback of fs.readFile
    var bufferString = buffer.toString(); 
    var bufferStringSplit = bufferString.split('\n'); 
  });
  callback();
}

function logMyNumber() {
  // Because the variables are in a closure above, bufferStringSplit is null here
  console.log(bufferStringSplit.length-1);
}

counter(logMyNumber);

Solution:

Declare the variables in the module's scope:

var fs = require('fs');
var pathToFile = process.argv[2];

// These can now be accessed from anywhere within the module
var bufferString, bufferStringSplit;

function counter(callback) {
  fs.readFile(pathToFile, function (err, data) {
    bufferString = data.toString(); 
    bufferStringSplit = bufferString.split('\n'); 
    callback();
  });
}

// bufferStringSplit should no longer return null here
function logMyNumber() {
  console.log(bufferStringSplit.length-1);
}

Problem 2: Callbacks

function counter(callback) {
  fs.readFile(pathToFile, function (err, data) {
    bufferString = buffer.toString(); 
    bufferStringSplit = bufferString.split('\n'); 

    // Place the callback WITHIN the other callback, otherwise they run in parallel
    callback();
  });
}

Problem 3: fs.readFile API

fs.readFile doesn't return anything, so your buffer variable below is null

function counter(callback) {      
  var buffer = fs.readFile(pathToFile, function (err, data) {
    bufferString = buffer.toString(); 
    bufferStringSplit = bufferString.split('\n'); 
  });
  callback();
}

Solution:

function counter(callback) {      
  fs.readFile(pathToFile, function (err, data) {
    // The data argument of the fs.readFile callback is the data buffer
    bufferString = data.toString(); 
    bufferStringSplit = bufferString.split('\n'); 
  });
  callback();
}

Finally, the code should look like:

var fs = require('fs');
var pathToFile = process.argv[2];

var bufferString, bufferStringSplit;

function counter(callback) {
  fs.readFile(pathToFile, function (err, data) {
    bufferString = data.toString(); 
    bufferStringSplit = bufferString.split('\n'); 
    callback();
  });
}

function logMyNumber() {
  console.log(bufferStringSplit.length-1);
}

counter(logMyNumber);

Solution 2

Same problem for me. This is my solution.

var fs = require('fs');
var file = process.argv[2];

function count(pFile, callback) {
  fs.readFile(pFile, "utf8", function(err, data){
     callback(data.split("\n").length-1);
  });
}

count(file, console.log);

Solution 3

Trying to treat errors as well. Not sure, if it is better to propagate the error in the last callback. I think the functionality is quite basic, but anyway I am propagating errors.

I would also say is more correct to delegate the split in the last callback rather than passing it through an argument or similar.

var fs = require('fs');
var myfile = process.argv[2];



function solution(file, callback){
fs.readFile(file, "utf-8", function (err, data) {
    if (err) callback(err);
    callback(null, data)
});
}

function mycallback(err,data){
  if (err) callback(err) console.error(err);
  return data.split('\n').length-1);
}

solution(myfile,mycallback)
Share:
30,195
enducat
Author by

enducat

Updated on March 29, 2020

Comments

  • enducat
    enducat about 4 years

    I'm trying to learn async programming and was struggling with lesson 4 of nodeschool.io with the implementation of an async io with callbacks.

    Basically, I'm trying to use fs.readFile to count the number of newlines within a file using a callback.

    Here's my code:

    var fs = require('fs');
    var pathToFile = process.argv[2];
    
    function counter(callback) {
        var buffer = fs.readFile(pathToFile, function (err, data) {
        var bufferString = buffer.toString();
        var bufferStringSplit = bufferString.split('\n');
      });
      callback();
    }
    
    function logMyNumber() {
      console.log(bufferStringSplit.length-1);
    }
    
    counter(logMyNumber);
    

    I understand that callbacks are executed once the line of code is finished executing, so shouldn't the

    var bufferString = buffer.toString();
    var bufferStringSplit = bufferString.split('\n');
    

    be called after fs.readFile() finishes reading the file from disk?

    Then finally the callback() calls logMyNumber, which should just output the number of lines the file has.