Using Filesystem in Node.Js with Async/Await

How to make fs.readFile async await?

To use await, you need to use promise versions of fs.readFile() and fs.readdir() which you can get on fs.promises and if you want these to run sequentially, then use a for loop instead of .map():

async function readingDirectory(directory) {
const fileNames = await fs.promises.readdir(directory);
for (let file of fileNames) {
const absolutePath = path.join(directory, file);
log(absolutePath);

const data = await fs.promises.readFile(absolutePath);
log(data);
}
}

readingDirectory(folder).then(() => {
log("all done");
}).catch(err => {
log(err);
});

How to read file with async/await properly?

To use await/async you need methods that return promises. The core API functions don't do that without wrappers like promisify:

const fs = require('fs');
const util = require('util');

// Convert fs.readFile into Promise version of same
const readFile = util.promisify(fs.readFile);

function getStuff() {
return readFile('test');
}

// Can't use `await` outside of an async function so you need to chain
// with then()
getStuff().then(data => {
console.log(data);
})

As a note, readFileSync does not take a callback, it returns the data or throws an exception. You're not getting the value you want because that function you supply is ignored and you're not capturing the actual return value.

How to use async/await with file system module

You can "promisefy" all callback style functions!

// promisefy this:
fs.unlink('path/file.txt', (err) => {
if (err) throw err;
console.log('path/file.txt was deleted');
});

// to this:
const unlinkPromise = (path) => new Promise((resolve, reject) => {
fs.unlink('path/file.txt', (err) => {
if (err) reject(err);
resolve(path);
});

});

// and then call with await or chain promises
await unlinkPromise('path/file.txt').then((path) => {
console.log(`${path} was deleted`);
});

But as already mentioned, the sync method does not require await, this strategy, I would recommend for promise cascades...

Node.js read file using async/await

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).

readFile async await in nodejs

The readFile() is non-blocking so you're calling res.end() BEFORE you call res.write(). I'd suggest using await like this:

const server = http.createServer(async (req, res) => {
if(req.url === `/`){
try {
const data = await readDemo(`./todo.html`);
res.writeHead(200,{"Content-type":"text/html"});
res.write(data)
res.end();
} catch(e) {
console.log(e);
res.writeHead(500);
res.end();
}
} else {
res.writeHead(404);
res.end();
}
});

Without await, you need to move the res.end() inside of the .then():

const server = http.createServer((req,res)=>{
if(req.url === `/`){
readDemo(`./todo.html`).then(data => {
res.writeHead(200,{"Content-type":"text/html"});
res.write(data);
res.end();
}).catch(err => {
console.log(err);
res.writeHead(500);
res.end();
});
} else {
res.writeHead(404);
res.end();
}
});

FYI, in modern versions of node.js fs.promises.readFile() is already a promise version so you don't have to make your own.

Is it ever better to use Node's filesystem sync methods over the same async methods?

It depends on the situation. The main benefit of the sync methods is that they allow for easier consumption of their results, and the main disadvantage is that they prevent all other code from executing while working.

If you find yourself in a situation where other code not being able to respond to events is not an issue, you might consider it to be reasonable to use the sync methods - if the code in question has no chance of or reason for running in parallel with anything else.

For example, you would definitely not want to use the sync methods inside, say, a server handling a request.

If your code requires reading some configuration files (or creating some folders) when the script first runs, and there aren't enough of them such that parallelism would be a benefit, you can consider using the sync methods.

That said, even if your current implementation doesn't require parallelism, something to keep in mind is that, if the situation changes and you find that you do actually need to allow for parallel processing, you won't have to make any changes to your existing code if you had started out by using the promise-based methods in the first place - and if you understand the language, using the Promises properly should be pretty easy, so if there's a chance of that, you might consider using the Promises anyway.



Related Topics



Leave a reply



Submit