Reputation: 127
I have a text file which simply lists some URL's. I'm trying to take each line from the text file, and add it to an array of urls for further operation.
var fs = require('fs'),
Urls = [];
var returnURLS = function(file) {
var read = function(callback) {
fs.readFile(file, function(err, logData){
if (err) throw err;
var text = logData.toString();
var lines = text.split('\n');
lines.forEach(function(line, callback){
var url = "http://www." + line;
Urls.push(url);
});
callback();
});
};
var giveBackAnswer = function() {
console.log("1: ", Urls);
return Urls;
};
read(giveBackAnswer);
};
console.log("2: ", returnURLS('textFileWithListOfURLs.txt'));
My console output clearly shows that the file system operations have not completed by the time the program is supposed to log the results, but that the results eventually do show up.
2: the urls are undefined
1: [ 'http://www.cshellsmassage.com',
'http://www.darsanamartialarts.com',
'http://www.davidgoldbergdc.com',
'http://www.dayspaofbroward.com',.... (etc)
What is the best way to get these functions to operate synchronously? 1) Compile the Urls array through file system operations 2) Print the array to the console once it has been filled
Upvotes: 0
Views: 422
Reputation: 382404
You could use fs.readFileSync
in that simple case :
var returnURLS = function(file) {
var text = fs.readFileSync(file).toString();
var lines = text.split('\n');
lines.forEach(function(line, callback){
var url = "http://www." + line;
Urls.push(url);
});
return Urls;
};
That's perfectly OK when you don't need parallelism, like in this small utility program.
But the solution you'll reapply everywhere else is to be wholly asynchronous by not returning the result but passing it as argument to a callback :
var fetchURLS = function(callback) {
fs.readFile(file, function(err, logData){
if (err) throw err;
var text = logData.toString();
var lines = text.split('\n');
lines.forEach(function(line, callback){
var url = "http://www." + line;
Urls.push(url);
});
callback(Urls);
});
};
};
fetchURLS('textFileWithListOfURLs.txt', function(urls){
console.log("2: ", urls);
});
When your code grows in complexity, it becomes convenient to use promises to reduce the "callback hell".
Upvotes: 1
Reputation: 312
Wrap the function with a callback
var fs = require('fs'),
Urls = [];
function doit(cb){
var returnURLS = function(file) {
var read = function(callback) {
fs.readFile(file, function(err, logData){
if (err) throw err;
var text = logData.toString();
var lines = text.split('\n');
lines.forEach(function(line, callback){
var url = "http://www." + line;
Urls.push(url);
});
callback();
});
};
var giveBackAnswer = function() {
console.log("1: ", Urls);
return Urls;
};
read(giveBackAnswer);
};
cb(returnURLS);
}
doit(function(result){
console.log("2: ", result('textFileWithListOfURLs.txt'));
});
Upvotes: 0
Reputation: 276496
Well, your function takes returns undefined
. This is because all functions in JavaScript return undefined
.
If you would like to hook on your function using callbacks, it has to take a callback itself and then you'd place your continuation in that callback:
var returnURLS = function(file, whenDone) {
var read = function(callback) {
fs.readFile(file, function(err, logData){
if (err) whenDone(err);
var text = logData.toString();
var lines = text.split('\n');
lines.forEach(function(line, callback){
var url = "http://www." + line;
Urls.push(url);
});
callback();
});
};
var giveBackAnswer = function() {
console.log("1: ", Urls);
whenDone(null, Urls);
};
read(giveBackAnswer);
};
Which would let you do:
returnURLS("textFileWithList.txt", function(err, list){
console.log("2: ", list);
});
The alternative solution using promises (bluebird) would look something like:
var fs = Promise.promisify(require("fs"));
var returnURLS = function(file) {
return fs.readFileAsync(file).then(function(logData){
var text = logData.toString();
var lines = text.split('\n');
return lines.map(function(line){
return "http://www." + line;
});
});
};
Which would let you do:
returnURLS("url.txt").then(function(data){
console.log("Got data!", data);
});
Upvotes: 1