Skip to content
Advertisement

How to log return value after async/await?

Below have I pasted in PoC code, where I have removed lots of lines, but it shows the problem/question I am facing.

createPost() returns a “post number” in the ret variable. I don’t need the “post number for anything else than logging it.

With the current implementation, I have to define ret outside of the while loop, and since sequential code is run before asynchronous code in the NodeJS event loop, I expect the logging will be executed before createPost(), which is not what I want.

Question

Is it possible to only log ret when createPost() have been executed?

module.exports = async (p) => {
  let ret = 0;

  try {

    while (true) {

      switch (x) {
        case 1:
          isOk = await getStatusCode({ ... });
          break
        case 2:
          isOk = await getString({ ... });
          break
        default:
          throw "";
      };

    ret = await createPost(p);
    appLogger.info(`Created post: ${ret}`);   // I don't need 'ret' for anything else than logging it

  } catch (error) {
    appLogger.error(error);
  }
}

createPost.js

const axios = require('axios');

module.exports = async (c) => {
  try {
    const r = await axios({ ... });
    return r.data.key;
  } catch (error) {
    throw new Error(JSON.stringify(error.response.data, null, 2));
  };

};

Advertisement

Answer

…and since sequential code is run before asynchronous code in the NodeJS event loop, I expect the logging will be executed before createPost(), which is not what I want.

All of the code in an async function after the first await is asynchronous, not synchronous. In your code, the appLogger.info call won’t happen until createPost has finished its work (asynchronously).

So there’s no need to declare ret outside the loop (and even if the above weren’t true, that wouldn’t really help), you can just do it inline, see *** comments:

module.exports = async (p) => {
  // *** No `ret` here

  try {

    while (true) {

      switch (x) {
        case 1:
          isOk = await getStatusCode({ ... });
          break
        case 2:
          isOk = await getString({ ... });
          break
        default:
          throw "";
      };

    const ret = await createPost(p); // *** Declare it here
    appLogger.info(`Created post: ${ret}`);

  } catch (error) {
    appLogger.error(error);
  }
}

The code waits, asynchronously, at the await and only continues when createPost is done.

Here’s a simplified example:

const randomDelay = () => new Promise(resolve => {
    setTimeout(resolve, Math.floor(Math.random() * Math.floor(Math.random() * 300) + 500));
});

async function doSomethingElse() {
    await randomDelay();
}

async function createPost(i) {
    await randomDelay();
    return i * 2;
}

async function example(max) {
    console.log("Starting (this log is synchronous)");
    for (let i = 0; i < max; ++i) {
        await doSomethingElse();
        const ret = await createPost(i);
        console.log(`i = ${i}, ret = ${ret}`);
    }
    console.log("All done");
}

console.log("Calling example");
example(5)
.then(() => {
    console.log("example promise fulfilled");
})
.catch(error => {
    console.error("example promise rejected", error);
});
console.log("Done calling example, it's running asynchronously");

Technically, you don’t need ret at all, this would also work:

appLogger.info(`Created post: ${await createPost(p)}`);

but if it were me, I’d keep it as shown in the first code block above. It’s easier to debug.

User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement