Simple nodejs callback example with fs.readFile
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)
enducat
Updated on March 29, 2020Comments
-
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.