Home > Enterprise >  Asynchronous file reading, cannot make function finish before returning
Asynchronous file reading, cannot make function finish before returning

Time:01-10

I am trying to read all files in folder, check if it has featured: true prop, increase the counter if it does and then throw error if there is more than 1 such file. But for some reason, my code doesn't wait and simply jumps to last section, this is the output

this should be last
Inside item, looking for featured prop
Inside item, looking for featured prop

My code:

const fs = require('fs');
const findInDir = require('./utils/findInDir');

(async () => {
  const dir = './public/page-data/blog';
  const fileRegex = /.*/;
  const allFiles = findInDir(dir, fileRegex);
  let result = 0;

  await allFiles.map(file => {
    fs.readFile(file, 'utf8', (err, data) => {
      const obj = JSON.parse(data);

      if (obj.result.pageContext.featured === true) {
        console.log('Inside item, looking for featured prop');
        result  = 1;
      }
    });
  });

  console.log('this should be last');

  if (result > 1) {
    throw new Error('There are multiple featured blog posts, please fix.');
  }
})();

Need some help understanding what am I doing wrong.

CodePudding user response:

You need to use the non-callback version of fs.readFile in order to actually await reading the file. Also using .map does not make a lot of sense as you're not actually mapping something, so simply use a for .. of loop:

for (const file of allFiles){
 try {
   const data = await fs.promises.readFile(file);
   // ...
 } catch(err) {
   // handle error
 }
}

console.log('this should be last');

CodePudding user response:

Quick solution:

(async () => {
  const dir = "./public/page-data/blog";
  const fileRegex = /.*/;
  const allFiles = findInDir(dir, fileRegex);

  try {
    await Promise.all(
      allFiles.map((file) => {
        return new Promise((resolve, reject) => {
          fs.readFile(file, "utf8", (err, data) => {
            const obj = JSON.parse(data);

            if (obj.result.pageContext.featured === true) {
              reject("Inside item, looking for featured prop");
            } else {
              resolve();
            }
          });
        });
      })
    );
  } catch (err) {
    throw new Error("There are multiple featured blog posts, please fix.");
  }
})();

Instead of checking every item one by one like in an loop i do it like this. It checks "parallel" if any of them has featured set to true. Therefore its faster then a loop

If its true i reject it and the Promise.all() stops. The try / catch of the Promise.all() catches the rejection


You need to understand just 1 thing to know when to use await and when not.

It only makes sense to use await on promises.

How do you know if its an promise? Just console.log it

Does it console log Promise? Use await

Does it NOT console log Promise? It makes no sense to use await

enter image description here

This returns just an array. Does it makes sense to use await? No, it does not return an Promise

But if you do it like this:

enter image description here

You have an array of promises. Here is a bit different. You have an array BUT the elements inside are an promise. You can use Promise.all() it basically awaits for every item in the array until its done.

  •  Tags:  
  • Related