0

I have read some documentation on async/await and tried coming with an example to understand it better. What I was expecting is that the below code without async and await would print first the string 'Completed', followed by the content of the file. But even after adding async and await, I see that the printing order is unaffected. My impression was async and await usage in this case would print the file contents first followed by the string 'Completed'.

var fs = require('fs');

getTcUserIdFromEmail();

async function getTcUserIdFromEmail( tcUserEmail ) {

    let userInfo = {};
    let userFound = false;
    // Read the file that is containing the information about the active users in Teamcenter.
    await fs.readFile('tc_user_list.txt', function(err, data) {

        if( err )
        console.log( err );
        else
        console.log( data.toString() );
    });

    console.log( 'Completed method');
}

Request you to point out what I am doing wrong.

Thanks, Pavan.

Pavan Dittakavi
  • 3,013
  • 5
  • 27
  • 47
  • What do you think `await` does? Why are you mixing it and callbacks? – Joseph Sible-Reinstate Monica May 24 '20 at 05:37
  • 1
    `fs.readFile()` doesn't return a promise. [Using filesystem in node.js with async / await](https://stackoverflow.com/questions/40593875/using-filesystem-in-node-js-with-async-await) – Guy Incognito May 24 '20 at 05:38
  • 1
    `await` ONLY does anything useful when you await a promise. The regular version of `fs.readFile()` does not return a promise so awaiting it does nothing useful. You can use `fs.promises.readFile()` and it will return a promise and does NOT accept a callback. The result comes back from the awaited promise, not via a callback. – jfriend00 May 24 '20 at 05:41
  • @GuyIncognito It works using fs.promises as mentioned in the other thread. Thanks. – Pavan Dittakavi May 24 '20 at 05:45
  • @jfriend00 I now understand that await works only when the method it is waiting for returns a promise. Although fs.promises.readFile() works, what did you mean by it not accepting a callback?. I am using this line of code 'await fsPromises.readFile('tc_user_list.txt', function(err, data) {' and it is using a callback right. Please explain. – Pavan Dittakavi May 24 '20 at 05:46
  • 1
    `fs.promises.readFile()` does NOT accept a callback. Look at [the documentation](https://nodejs.org/api/fs.html#fs_fspromises_readfile_path_options). The result or error comes back in the promise, not in a callback. If you pass it a callback, that callback will NEVER get called. When you program with promises, you get your result or error back in the promise. When you await a promise, you get the result as `const data = await fs.promises.readFile(someFile)` and you would catch the error with a `try/catch`. – jfriend00 May 24 '20 at 05:51
  • @jfriend00 I read the documentation and it is not accepting a callback as you have stated. I am not sure why it worked earlier, perhaps an undefined behavior. At any cost it is accurate to stick to the API contract of the method. Thanks for helping me out. – Pavan Dittakavi May 24 '20 at 06:30

1 Answers1

2

await only works if the expression being awaited returns a Promise. fs.readFile does not return a promise, so right now your await doesn't do anything.

Luckily for us, node provides a function fs.promises.readFile that is like fs.readFile but instead of expecting a callback, returns a promise.

const fs = require('fs')

Now you can await fs.promises.readFile(...)

getTcUserIdFromEmail(); // > contents_of_tc_user_list
                        //   Completed method

async function getTcUserIdFromEmail( tcUserEmail ) {
    let userInfo = {};
    let userFound = false;
    const data = await fs.promises.readFile('tc_user_list.txt')
    console.log(data.toString())
    console.log( 'Completed method');
}
richytong
  • 2,387
  • 1
  • 10
  • 21
  • No need to promisify `fs.readFile()` when `fs.promises.readFile()` is already there. Also, you need to show that calling `getTcUserIdFromEmail()` itself needs to use `await` or `.then()` to know when it's done because it returns a promise too. – jfriend00 May 24 '20 at 05:54
  • @jfriend00 Pardon me, but from what I understand, for every async method, the caller of the async method should have to 'await' it. This is because there is no callback. Is this understanding correct. – Pavan Dittakavi May 24 '20 at 05:56
  • If you just want to see the log messages, you don't have to await `getTcUserIdFromEmail()`. Your node process will exit when all the async stuff resolves. You absolutely have to await if you want to use the return value of `getTcUserIdFromEmail()`, however – richytong May 24 '20 at 05:58
  • @jfriend00 I didn't know about `fs.promises`, I will update my answer to use that, thank you! – richytong May 24 '20 at 05:59
  • @PavanDittakavi - If you want to know when an asynchronous function that returns a promise is done or if it had errors, you have to use `await` with `try/catch` around it or or `.then()` and/or `.catch()`. – jfriend00 May 24 '20 at 06:17