Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simple nodejs callback example with fs.readFile

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.

like image 660
enducat Avatar asked Feb 21 '26 09:02

enducat


1 Answers

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);
like image 151
srquinn Avatar answered Feb 22 '26 23:02

srquinn



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!