Hacker News new | ask | show | jobs
by tlrobinson 5381 days ago
I really like this idea, but it doesn't seem to do error handling correctly.

This is not going to catch most errors occurring in an asynchronous APIs:

    try {
      asyncOperation(function(err, result) {
         // ...
      });
    } catch (e) {
      // ...
    }
Most errors will occur asynchronously, thus the convention of "err" being the first argument to asynchronous API callbacks in Node.

Unless this supports that convention, your code should actually look like:

    async function magic() {
      try {
        // code here
        await err, bar = doSomething();
        if (err) {
          throw err;
        }
        // more code here
        await err, boo = doAnotherThing();
        if (err) {
          throw err;
        }
        // do even more stuff here
      }
      catch (e) {
        // handle the error
      }
    }
...or something similar. It's better than the alternative, but not great.

This certainly could support the "err" first convention, but APIs that don't use that convention wouldn't work correctly.

1 comments

Not necessarily. A callback function with the standard signature under the hood is implied. If the author is controlling flow into and out of these execution contexts there is no reason an error passed to the implicit callback cannot cause an exception to be thrown into the original execution. Throwing exceptions into coroutines is a fairly normal pattern.
True, but the existing Node APIs don't do that, they return the error as an argument to the callback.
The wiki page says:

    // these two lines are equivalent
    await a, b, c, d = moo(1, 2, 3);
    moo(1, 2, 3, function(a, b, c, d) {} );
So I don't see why not...

    // ...these two lines would be also equivalent
    await error, foo = bar(1, 2, 3);
    bar(1, 2, 3, function(error, foo) {} );
Exactly. The error object is a return value of the "await"-ed function, not an exception that's thrown.

Here's a concrete example. Normally in Node you do something like this:

  fs.readFile('/etc/passwd', function (err, data) {
    if (err) {
      // handle error
    }
    // normal processing
  });
The await version would look like this:

  await err, data = fs.readFile('/etc/passwd');
  if (err) {
    // handle error
  }
  // normal processing
Ideally it would look like this:

  try {
    await data = fs.readFile('/etc/passwd');
    // normal processing
  } catch (error) {
    // handle error
  }
This is certainly something that is doable and crossed my mind, but I did not want to have the await be restricted to functions that conform to the typical return arguments. For now at least.
How about

  try await foo = bar(baz)
as shorthand for

  await error, foo = bar(baz)
  if (error) throw error