3

I am studying callbacks, and for some reason I can't get it right... I want to read a file, and save it's data to a global variable to play with later.

Here is what I have so far:

var fs = require("fs");
var readline = require("readline");
var i = 0;
var total = 66; //put the total foldernames or total images (same number)
var folder_names = [];
var data = [];

lineReader = readline.createInterface({
    input: fs.createReadStream("folder-names and data.txt")
});


lineReader.on('line', function(line, dataCollector) {
    if(i<66)
        folder_names.push(line);
    else
        data.push(line);

    dataCollector(folder_names, data);
    i++;
});

var dataCollector = function(folder_names, data) {
    //console.log(folder_names);
}

console.log(folder_names[0]); //should have a value now.

What is wrong? I get: dataCollector is not a function

Florin Pop
  • 5,105
  • 3
  • 25
  • 58

2 Answers2

7

You're shadowing the dataCollector identifier here:

lineReader.on('line', function(line, dataCollector) {

That declares dataCollector as the second parameter to your callback, shadowing (hiding) the identifier at the top level of your script.

The line event doesn't document that it provides a second argument to its callback, so it should look like this:

lineReader.on('line', function(line) {

Re your extension of the question:

console.log(folder_names[0]); //should have a value now.

No, it shouldn't. Why: How do I return the response from an asynchronous call?

In your case, you probably want to do your console.log in an close event handler:

lineReader
    .on('line', function(line) {
        if(i<66)
            folder_names.push(line);
        else
            data.push(line);

        dataCollector(folder_names, data);
        i++;
    })
    .on('close', function() {
        console.log(folder_names[0]); // has its values now
    });
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • I want to get the folder_names variable filled in into the lineReader function. I'll update my question. – Florin Pop Sep 30 '16 at 11:42
  • @FlorinPop: Your question is currently about why you're getting the error *"dataCollector is not a function"*. Questions are not meant to be moving targets. This answers that question. – T.J. Crowder Sep 30 '16 at 11:45
  • I told in the description what I want: 'I want to read a file, and save it's data to a global variable to play with later.' – Florin Pop Sep 30 '16 at 11:45
  • @FlorinPop: The focus is on the error message. I've added a note about your edit above. – T.J. Crowder Sep 30 '16 at 11:46
  • The focus is not on the error message. I am struggling to get the variable outside the lineReader function, so I can manipulate it later. But thank you! – Florin Pop Sep 30 '16 at 11:48
  • @FlorinPop: When you post a question and say "But I'm getting this error," that's the focus of the question. In any case, the linked question explains why you can't do it the way you're doing it, and what to do instead; the above addresses why you're getting the error. – T.J. Crowder Sep 30 '16 at 11:49
  • Anyway... I saw those king of post before but I don't understand how to use it in my own example. Thank you anyway :) I've marked your as correct. – Florin Pop Sep 30 '16 at 11:52
  • @FlorinPop: You'd use `folder_names` in a function that you call (or have called) once all the names have been read, probably in the `readline`'s `close` event; see above. – T.J. Crowder Sep 30 '16 at 11:56
  • @T.J.Crowder, I tried following this thread but I am still having trouble accessing the variable outside the lineReader function. I'm hoping you can help. I just asked a similar question here today and have not received an answer: https://stackoverflow.com/questions/59915191/how-to-create-an-array-entry-for-each-line-of-a-text-file-using-node-js/59915239?noredirect=1#comment105955276_59915239 – Nakul Tiruviluamala Jan 26 '20 at 08:57
0

You declare your function using var which will be done when the line is reached. So when you call it in your callback, the function has not been defined yet. To be able to use it, either move it before lineReader.on('line', function(){}) or (better) define it like that:

function dataCollector(folder_names, data) {
  /* Your function */
}

Doing it this way, your function is declared before your script is executed, and thus it exists when you reach your callback.

Max G.
  • 266
  • 1
  • 6
  • *"You declare your function using var which will be done when the line is reached. So when you call it in your callback, the function has not been defined yet."* No, that's incorrect, but it's understandable why you would get there. That would only be the case if `readLine` called its callback *synchronously*, but it doesn't. It's poor practice to put things in the order they are in the question, but `dataCollector` will have its value by the time the callback is called. – T.J. Crowder Sep 30 '16 at 11:47
  • Yest it is: see _Function declaration hoisting_ in https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/function. Still, the issue here is the shadowing as pointed out. – Max G. Sep 30 '16 at 11:55
  • ***sigh*** Yes, I know how function declarations work. I'm saying that what you've said about the OP's code is incorrect. Because it's incorrect. I also quite clearly said *why* it's incorrect. – T.J. Crowder Sep 30 '16 at 11:57
  • 1
    Sorry, misread your post. I agree with you :). But as you pointed out, my point was that I don't think the order in which the function is declared is correct (but I might be wrong). – Max G. Sep 30 '16 at 11:59
  • It's not ideal, but it's not *incorrect*, and does work; the function *is* defined when the OP calls it: https://jsfiddle.net/ef4s10dr/ (It wouldn't be for a synchronous callback like the one `Array#sort` uses.) The actual problems the OP was having were completely unrelated to that. – T.J. Crowder Sep 30 '16 at 12:04