Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.js read file using async/await

I am experimenting with async/await code to read file. Here's my code:

var fs = require('fs');

function readFile(fileName) {
  return new Promise(resolve => {
    //console.log(test);
    fs.readFile(fileName, 'utf8', function (err, data) {
      if (err) throw err;

      console.log(fileName)
      console.log(data)
    })
    resolve();
  });
}

async function run() {
  await readFile('file1.txt');
  await readFile('file2.txt');
  readFile('file3.txt');
}

run();

But the result is still random. It means file3 sometime read before file2. Where am I doing wrong?

like image 785
roscoe_x Avatar asked Jan 04 '19 07:01

roscoe_x


People also ask

How do I read a node JS asynchronous file?

readFileSync() method is an inbuilt application programming interface of fs module which is used to read the file and return its content. In fs. readFile() method, we can read a file in a non-blocking asynchronous way, but in fs. readFileSync() method, we can read files in a synchronous way, i.e. we are telling node.

Can we use await on FS readFile?

To read file with async and await in Node. js, we can use the promise version of fs. readFile .

How do you read a file asynchronously?

For reading a file asynchronously there are two versions of read() method in the AsynchronousFileChannel class. read() method that returns a Future. read() method where you can pass CompletionHandler instance as an argument.

Can I use async await in node?

Async functions are available natively in Node and are denoted by the async keyword in their declaration. They always return a promise, even if you don't explicitly write them to do so. Also, the await keyword is only available inside async functions at the moment – it cannot be used in the global scope.


2 Answers

There are many ways to achieve that.

Most of them is explained in this link


I'll write simple one:

1) using util.promisify to convert callback method to promise:

const fs = require('fs');
const util = require('util');
const readFile = (fileName) => util.promisify(fs.readFile)(fileName, 'utf8');

(async () => {
  try {
    const files = ['file1.txt', 'file2.txt', 'file3.txt'];
    for (const file of files) {
      console.log(
        await readFile(file)
      );
    }
  }
  catch (error) {
    console.error(error);
  }
})();

2) *Sync methods. Since Your code is not dealing with concurrency You can use *Sync methods:

const fs = require('fs');

try {
  const files = ['file1.txt', 'file2.txt', 'file3.txt'];
  for (const file of files) {
    console.log(
      fs.readFileSync(file, 'utf8')
    );
  }
}
catch (error) {
  console.error(error);
}


BTW. Here is Your fixed code:

var fs = require('fs');

function readFile(fileName) {
  return new Promise((resolve, reject) => {
    fs.readFile(fileName, 'utf8', function (error, data) {
      if (error) return reject(error);

      console.log(fileName)
      console.log(data)

      resolve();
    })
  });
}

async function run() {
  await readFile('file1.txt');
  await readFile('file2.txt');
  await readFile('file3.txt');
}

run();

since You're calling readFile and resolve at same async sequence it's being called at same time which is reason of race condition.

You've to wait for callback handling and then resolve it (inside callback scope).

like image 163
num8er Avatar answered Sep 20 '22 12:09

num8er


There are a couple options with native node functionality

A) With the fs.promises API

You can use destructuring assignment on import to alias fs.promises as just fs

const { promises: fs } = require("fs");

(async () => {
    try {
        let file1 = await fs.readFile("file1.txt", "utf-8");
        let file2 = await fs.readFile("file2.txt", "utf-8");

    } catch (e) {
        console.log("e", e);
    }
})()

B) With util.promisify API

const fsSync = require("fs");
const {promisify} = require("util")

const fs = {
  readdir: promisify(fsSync.readdir),
  readFile: promisify(fsSync.readFile),
  // etc
};

(async () => {
    try {
        let file1 = await fs.readFile("file1.txt", "utf-8");
        let file2 = await fs.readFile("file2.txt", "utf-8");

    } catch (e) {
        console.log("e", e);
    }
})()

Further Reading

  • How to read file with async/await properly?
  • Using filesystem in node.js with async / await
like image 28
KyleMit Avatar answered Sep 18 '22 12:09

KyleMit