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?
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.
To read file with async and await in Node. js, we can use the promise version of fs. readFile .
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.
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.
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).
There are a couple options with native node functionality
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);
}
})()
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);
}
})()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With