0

I'm trying to read some .txt files and console.log an object with the formatted data after that, but idk how to do this with async/await. I tried this but then just got the error "SyntaxError: Unexpected reserved word"

let parse = async(num) =>{
    let files = ['p.txt', 'q.txt', 'r.txt', 's.txt', 't.txt', 'u.txt', 'v.txt', 'w.txt', 'x.txt', 'z.txt'];
        fs.readFile('./data txt/' + files[num], 'utf8', (err, data) => {
            if(err){
                console.log(err)
            }
            await test(obj, 'data', data) 
        });
};


parse(0); // need to end so that console.log() catch the new obj 
console.log(obj)
retr0
  • 55
  • 4
  • You have to use `await` inside an `async` function--nesting doesn't count, it has to be the same function itself. In any case, I don't think `async` will help you promisify this. Better to return a promise and use `resolve(data)` as shown [here](https://stackoverflow.com/questions/34628305/using-promises-with-fs-readfile-in-a-loop). Then the caller can `await` the promise (or use `.then`). – ggorlen Dec 17 '20 at 21:20

2 Answers2

1

Your nested callback isn't async (note: the following snippet just illustrates a solution to this specific problem, but full solution will be below):

let parse = (num) =>{
    let files = ['p.txt', 'q.txt', 'r.txt', 's.txt', 't.txt', 'u.txt', 'v.txt', 'w.txt', 'x.txt', 'z.txt'];
        fs.readFile('./data txt/' + files[num], 'utf8', async (err, data) => {
            if(err){
                console.log(err)
            }
            await test(obj, 'data', data) 
        });
};

That's why you get the SyntaxError.

In order to make the entire function async, you'll have to get rid of the callback-style fs.readFile(). You can use fs.promises (available since Node 10 I think):

let parse = async (num) =>{
    let files = ['p.txt', 'q.txt', 'r.txt', 's.txt', 't.txt', 'u.txt', 'v.txt', 'w.txt', 'x.txt', 'z.txt'];
    try {
      const data = await fs.promises.readFile('./data txt/' + files[num], 'utf8')
      return await test(obj, 'data', data) 
    } catch (err) {
      console.log(err);
    }
};

Or if you can't use this new API, you can use util.promisify():

const readFileAsync = require('util').promisify(fs.readFile);
let parse = async (num) =>{
    let files = ['p.txt', 'q.txt', 'r.txt', 's.txt', 't.txt', 'u.txt', 'v.txt', 'w.txt', 'x.txt', 'z.txt'];
    try {
      const data = await readFileAsync('./data txt/' + files[num], 'utf8')
      return await test(obj, 'data', data) 
    } catch (err) {
      console.log(err);
    }
};

Or, if you feel savvy (don't!), you can promisify the function yourself and using raw Promise:

let parse = (num) => new Promise((resolve, reject) => {
    let files = ['p.txt', 'q.txt', 'r.txt', 's.txt', 't.txt', 'u.txt', 'v.txt', 'w.txt', 'x.txt', 'z.txt'];
        fs.readFile('./data txt/' + files[num], 'utf8', (err, data) => {
            if(err){
                console.log(err)
            }
            resolve(test(obj, 'data', data));
        });
});
Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77
  • This will not work because you are not resolving the call to `parse(0)` – doublesharp Dec 17 '20 at 21:26
  • I tried to not touch code that's not related – Chayim Friedman Dec 17 '20 at 21:27
  • Would need to be `await parse(0)` in an async function or `parse(0).then((result) => ...)` – doublesharp Dec 17 '20 at 21:27
  • I think the question is mainly about how to log the results of the call to `parse()` if you look at the comment at the end – doublesharp Dec 17 '20 at 21:28
  • I don't think so. Removed that code to clarify that I'm not talking about it – Chayim Friedman Dec 17 '20 at 21:29
  • If it is, it's a duplicate of maybe thousand other questions – Chayim Friedman Dec 17 '20 at 21:30
  • This is the main one: https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call – Chayim Friedman Dec 17 '20 at 21:30
  • Can you please emphasise that the first snippet is not a suggestion/solution but only an explanation where the `async` was missing? Also I wouldn't recommend the last snippet since the other two approaches are so much better and simpler. – Bergi Dec 17 '20 at 21:35
  • 1
    Notice that using `data` outside of the `try` block won't work, although this just replicates the problem that already existed in the original code. I would recommend not to try handling the filesystem error in `parse` at all. – Bergi Dec 17 '20 at 21:37
  • @Bergi Thanks, I didn't noted that. I would recommend that too, but as I said, I tried to not touch existing infrastructure. – Chayim Friedman Dec 18 '20 at 11:30
  • 1
    @Bergi Added a note that the first snippet just illustrated the reason for the `SyntaxError`, and that you shouldn't feel savvy ;) – Chayim Friedman Dec 18 '20 at 11:34
0

You can wrap the callback for fs.readFile in a Promise and then resolve or reject the results.

Wrap the call to parse() in an anonymous async function to be able to use await.

const parse = async (num) => {
  let files = ['p.txt', 'q.txt', 'r.txt', 's.txt', 't.txt', 'u.txt', 'v.txt', 'w.txt', 'x.txt', 'z.txt'];
  return new Promise((resolve, reject) => {
    fs.readFile('./data txt/' + files[num], 'utf8', (err, data) => {
      if (err) {
        return reject(err);
      }
      return resolve(test(obj, 'data', data));
    });
  })
};

(async function() {
  const obj = await parse(0); // need to end so that console.log() catch the new obj 
  console.log(obj)
}());

/* 
// using thenables
parse(0).then((obj) => console.log(obj));
*/
doublesharp
  • 26,888
  • 6
  • 52
  • 73