0

I'm pretty new to Node.js and I had a confusing interaction with fs.readFile().

Initially, I thought that I could read a file using

fs.readFile("file.txt",function(err,data) {
    if(err) {throw err;}
    console.log(data);
});

However, this printed null. I consulted the documentation and it gives the exact same example and claims that it works fine!

Then I consulted stack overflow and found in this post and this post that a solution is to wrap fs.readFile() in your own function that takes a callback:

function read(file,callback) {
    fs.readFile("file.txt",function(err,data) {
        if(err) {throw err;}
        callback(data);
    });
}

read(file, function(data) {
    console.log(data);
});

Alternatively, it's possible to just assign data to a new variable:

var content;
fs.readFile("file.txt",function(err,data) {
    if(err) {throw err;}
    content = data;
    console.log(content);
});

My understanding is that when an asynchronous function completes and returns some value (here the contents of the file) then the callback runs on the returned data.

  1. If fs.readFile(file,callback) expects to be passed a callback function, then why does it seemingly run the callback before fs.readFile() has completed?

  2. Why does assigning the data to another variable change the way it behaves?

Thanks.

Community
  • 1
  • 1
Ivan Kelber
  • 336
  • 4
  • 13
  • Your initial code *does* work fine. Assuming you have `var fs = require("fs");` before it, and you have a file called "file.txt" in the current directory, it works. – Pointy Jan 30 '17 at 19:33
  • Hmm. I just tried again and it worked fine. I wonder what was causing my error before. – Ivan Kelber Jan 30 '17 at 20:07

1 Answers1

1
fs.readFile("file.txt",function(err,data) {
    if(err) {throw err;}
    console.log(data);
});

Would actually work. What wouldn't work is:

var content;
fs.readFile("file.txt",function(err,data) {
        if(err) {throw err;}
        content = data;
    });
console.log(content);

(which is the example that was in the post you had referenced)

And the reason is that fs.readLine is asynchronous to your code, meaning that the execution will carry on immediately without waiting for fs.readLine's response.

So in the case of the latter example,

console.log(content);  

would execute before fs.readLine returns with an answer (i.e. the callback is triggered).

In general, you cannot run asynchronous methods and expect them to have the answer right away, the whole idea of asynchronous is that it doesn't block, the execution/program carries on before the asynchronous method returns with an answer.

The whole purpose of the callback in asynchronous method is to provide a way for the method to notify you when it's done and feed you with the result.

wrapping fs.readLine doesn't solve the problem, it just provides a more clean interface for reading files (instead of calling "fs.readLine" you would just call "read")

areller
  • 4,800
  • 9
  • 29
  • 57
  • I guess the purpose of the cleaner interface is to help avoid whatever issue I was having in the first place :). Great explanation. – Ivan Kelber Jan 30 '17 at 20:08