13

I'm trying to get the following code to work:

'use strict';

var fs = require('fs');

var fileName = 'readme.txt';
var str = fs.readFile(fileName, 'utf8', function (err, data) {
    if (err) {
        console.log(err);
        throw err;
    }
    return data;
});

console.log('result read: ' + str);

readme.txt:

console.log('working');

I'm trying to display the following:

result read: console.log('working');
basickarl
  • 37,187
  • 64
  • 214
  • 335
  • 1
    This one of the most commonly asked things about asynchronous operations in Javascript. See the question this is marked a duplicate for a discussion of the options. You can't return a result directly from an async operation. In Javascript, you must use callbacks. – jfriend00 Jan 24 '16 at 20:00
  • @jfriend00 So I myself cannot turn a sync function into a async function (via js), is this somehow programmed on a lower level? – basickarl Jan 24 '16 at 20:03
  • You can't turn an asynchronous function into a synchronous function or vice versa. They are what they are. In the case of the `fs` module, this is programmed in native code in the `fs` library. An async function will be non-blocking and the result will ONLY be available sometime later via a callback. A synchronous function will be blocking and the result be directly available when it finishes blocking. You can sort of make a synchronous function seem like it might be asynchronous by just sending the return result via a callback, but it will still be blocking while performing its operation. – jfriend00 Jan 24 '16 at 20:25
  • @jfriend00 You mention `native code`, can you be more specific (I will be checking it :))? – basickarl Jan 24 '16 at 20:28
  • 1
    Here's the [node.js code on GitHub](https://github.com/nodejs/node) and [the native code for the `fs` module](https://github.com/nodejs/node/blob/master/src/node_file.cc) and here's [the JS interface](https://github.com/nodejs/node/blob/master/lib/fs.js) above it. – jfriend00 Jan 24 '16 at 20:31

3 Answers3

22

readFile is executed asynchronously, so data can only be accessed inside the callback function, if you want it to be synchronous, you should use readFileSync

Async:

'use strict';

const fs = require('fs');

const fileName = 'readme.txt';
fs.readFile(fileName, 'utf8', function (err, data) {
   if (err)
      return console.log(err);
   console.log('result read: ' + data);
});

Sync:

var str = fs.readFileSync(fileName, 'utf8'); // This will block the event loop, not recommended for non-cli programs.
console.log('result read: ' + str);

UPDATE

You can use util.promisify to convert fs.readFile from callback API to promise API.

const fs = require('fs');
const { promisify } = require('util');
const readFile = promisify(fs.readFile);

(async() =>  {
   try {
      const result = await readFile('readme.txt', 'utf8');
      consle.log(result);
   } catch(e) {
      console.error(e);
   }
})();

In Node 10 you can use fs/promises and avoid util.promisify

const fs = require('fs').promises;

(async() =>  {
   try {
      const result = await fs.readFile('readme.txt', 'utf8');
      consle.log(result);
   } catch(e) {
      console.error(e);
   }
})();
Boogie
  • 750
  • 7
  • 17
Marcos Casagrande
  • 37,983
  • 8
  • 84
  • 98
3

You're calling an asynchronous function. This means it does not wait to return when called and will, in this case, return undefined.

You can either use the readFileSync method to call it synchronously, or put your console.log in the callback

Joseph Young
  • 2,758
  • 12
  • 23
0

readFile is an async method (thus the callback.) You need the console.log (or anything you want to do with the result) in the callback for async functions. This is pretty much the backbone of node.js - by allowing async methods to be put onto the event loop, it keeps your code from being blocked.