2

I have several async callbacks which I'd like to try one after the other.

These are designed to throw an error if the asynchronous test they are running fails.

The tests check the privilege of a user from most to least. So if we're checking that a user is in a particular group, we first check if they are admin, then if they are no further checks are needed.

My instinct was to chain the catch blocks like this:

try {
  await userIsAdmin;
  next();
} catch(e) {
  await userIsInGroup(group);
  next();
} catch(e) {
  console.log('User is not admin or in the group');
}

I'm about to start nesting my try's and catches but I'm starting to smell a rat.

Is this a sensible approach to sequencing multiple asynchronous operations which may or may not throw an error?

5
  • 3
    using .then() and .catch() Commented Dec 10, 2018 at 19:32
  • @SebastianSpeitel Isn't the whole point of async/await to write async code in the same way as sync code. (i.e.no then/catch chains)?
    – LondonRob
    Commented Dec 10, 2018 at 19:35
  • there's nothing wrong with .then chains Commented Dec 10, 2018 at 19:36
  • @LondonRob could you fix the code with the missing } brackets?
    – noseratio
    Commented Dec 10, 2018 at 21:18
  • @noseratio Done!
    – LondonRob
    Commented Dec 11, 2018 at 16:18

2 Answers 2

1

A relatively neat solution, avoiding the .catch blocks acting as error handlers to calls to next() looks like this:

  getUser()
    .then(async () => {
      await userIsAdmin();
      next();
    })
    .catch(async () => {
      await userIsInGroup(group);
      next();
    })
    // etc...

This way the catch blocks act unambiguously as error handlers for the await statements, and not erroneously for the next() call too.

1
  • This is brilliant!
    – wizzwizz4
    Commented Dec 10, 2018 at 21:35
1

I'd refactor it like this:

if (
  await userIsAdmin().then(v => true, e => false)) || 
  await userIsInGroup(group).then(v => true, e => false)) )
{
  next();
}
else {
  console.log('User is not admin or in the group');
}

You can further log errors in the e => lambdas if you like:

await userIsAdmin().then(v => true, e => console.error(e)))

You could also reuse the onFulfilled/onRejected resolvers passed to then with a spread:

const toBoolean = [value => true, error => (console.error(error), false)];
if (
  await userIsAdmin().then(...toBoolean)) || 
  await userIsInGroup(group).then(...toBoolean)) )
{
  next();
}
else {
  console.log('User is not admin or in the group');
}
2
  • 1
    This is very neat. But I think my solution is more readable. If I came this code in a code base, I'd have to spend a while working out what it does. Think mine is pretty obvious.
    – LondonRob
    Commented Dec 11, 2018 at 16:17
  • @LondonRob, to each his own I suppose :) I like that await allows me to keep the linear structure of the codeflow and gives me an option to use if which is more readable to me than callbacks.
    – noseratio
    Commented Dec 11, 2018 at 20:27

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.