1

In an express route, I want to log a user's access to a db without:

  • waiting for it to finish before performing the task the user wants
  • caring about whether the logging was successful or not

I was wondering if the code does this correctly or not.

This thread (Down-side on calling async function without await) posted the same question essentially but the response was to avoid making the function async. However since sequelize's upsert returns a promise, I'm not sure if I did that properly in the code below. Can anyone verify?

I also noticed that if you don't await a promise in a async function's try-catch block, any errors thrown inside the promise will be unhandled. Because of that I made sure logAccess catches and handles any errors. Is this the right way to do things?

const { Router } = require('express');
const moment = require('moment-timezone');
const Sequelize = require('sequelize');

function timeout(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

const userTable = sequelize.define('user', {
  user_id: {
    type: Sequelize.UUID,
    primaryKey: true,
  },
  last_login: {
    type: 'TIMESTAMP',
  },
});

const logAccess = (user) => userTable.upsert({
  user_id: user.user_id,
  last_login: moment().tz('Australia/Sydney').format('YYYY-MM-DD HH:mm:ss'),
}).catch(() => console.log('Logging access to db failed'));

const makeCandy = async (user) => {
  await timeout(1000);
  return 'chocolate';
}

router.get('/get_candy', async (req, res) => {
  try {
    const user = req.body.user;
    // Log access without blocking thread
    logAccess(user);
    const candy = await makeCandy(user)
    res.status(200).send({ candy })

  } catch (e) {
    console.log(e);
  }
})
  • 1
    Yes, that's the way. I'm counting `resolve('chocolate');` as typo, though. – acdcjunior Sep 16 '19 at 07:36
  • I'm voting to close this question as off-topic because it best fits https://codereview.stackexchange.com/. – acdcjunior Sep 16 '19 at 07:37
  • 1
    `await` doesn't block the thread. It works like `yield` in that it pauses the function and restores the execution later. – VLAZ Sep 16 '19 at 07:40
  • Also, `await` is syntactic sugar over Promises - you can only await those, so you can re-write any `await` code into handling a Promise. `await` is a better alternatives some times in terms of how the code is laid out, it doesn't function radically differently. – VLAZ Sep 16 '19 at 07:42
  • The other question you found doesn't fit your bill, as you want error handling. It's never a good idea to have an asynchronous function that doesn't return a promise - as they wrote it's a `weirdFunction`. Yes, using `.catch()` like you did is OK, although I'd rather have placed it inside the route handler that calls `logAccess(user)` - just to be explicit about not awaiting it. – Bergi Sep 16 '19 at 07:59
  • @VLAZ I misused the terminology then. I meant to say I didn't want to wait for the `upsert` to finish before executing the rest of the code in the route. This then suggests concurrency with `Promise.all`. But `Promise.all` would wait for all the Promises to resolve and in this example, I didn't need to wait for `logAccess` to resolve. – trivial_tasks Sep 16 '19 at 09:04
  • @acdcjunior fixed that typo and thanks for the link to codereview. I could have phrased this question slightly differently without a working "attempt" so it suits this place though. – trivial_tasks Sep 16 '19 at 09:22

1 Answers1

2

It doesn't catch without awaiting:

const foo = () => Promise.reject('foo');

const bar = async() => {
  try {
    foo();
  } catch (e) {
    console.log('error caught');
  }
}

bar();

I at least get "Uncaught (in promise)".

I would catch errors promise-style

    logAccess(user).catch(someErrorHandlingFunction);

or in a separate function that I'm not awaiting:

const logAccessAndCatchErrors = async (user) => {
    try {
        await logAccess(user);
    } catch(e) {
// put something here
    }
}

//...
logAccessAndCatchErrors(user);  // not `await logAccessAndCatchErrors(user)`


mbojko
  • 13,503
  • 1
  • 16
  • 26