zenparsing / proposal-async-block

Eliminating the IIAAFE so you don't have to
6 stars 0 forks source link

What happens to rejections? #1

Open ljharb opened 6 years ago

ljharb commented 6 years ago

In an async function, any thrown exceptions or returned rejected promise ends up rejecting the overarching invocation’s promise.

What happens to uncaught exceptions from awaited values in an async block?

zenparsing commented 6 years ago

If this is really just sugar over an IIAAFE, then an uncaught exception would generate an unhandled promise warning.

Node still logs:

In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Do you know if Node is going to update this behavior soonish, so that unhandled rejection terminate the process?

ljharb commented 6 years ago

It’s very contested; the current situation is that they want to exit on GC of a promise with an unhandled rejection by default, but I’m hoping to continue arguing that this isn’t correct behavior ever. An unhandled rejection is not meant to terminate the process - Promise.reject() is a normal thing and it’s not the same as an uncaught exception - and i don’t think the language should advance a feature that promotes that.

Is there a reason that the block couldn’t produce a promise?

zenparsing commented 6 years ago

Is there a reason that the block couldn’t produce a promise?

There seems to be a general intuition that an async block ought to produce a value. (And that makes sense, if we are describing it as sugar over a immediately invoked function call!) We could make it an expression form instead of a statement form.

let p = async {
  await 1;
};

That leaves the question of precedence. Do you think this ought to work?

async {
  throw new Error('oops');
}.catch(e => {
  console.log(e.message);
});

(Note the . after the })

ljharb commented 6 years ago

yes, i would absolutely expect that to work.

bakkot commented 6 years ago

Do you think this ought to work?

I'm neutral on this, fwiw, given that

() => {}.call()

doesn't.

Edit: though, I expect async {...}.catch(e => ...) to be an extremely common pattern, so it would be nice if it worked.

ljharb commented 6 years ago

oh, to be clear, i would also be fine if wrapping parens were required.

PinkaminaDianePie commented 6 years ago

Wouldn't it be confusing if do and async expression will be independent? We'll have 2 totally separated flows for convertion of block to value, do for sync code and async expression for async code. Maybe it's worth to put more effort to do proposal instead to make async version of it?

zenparsing commented 5 years ago

@PinkaminaDianePie It would definitely be confusing if there were do expressions and async blocks. For many years I wanted there to be async do in addition to do, but the thread at https://github.com/tc39/proposal-do-expressions/issues/34 has changed my mind. Based on that analysis I don't think that do-expressions will help users write more maintainable code.

PinkaminaDianePie commented 5 years ago

@zenparsing thank you so much for this link! I read this analysis and changed my mind about do blocks (and already replaced them to IIFEs in my code). I just used do for simplest cases and never thought about that flow control statements in it can control outer scope. And harder cases with implicit return makes code unmaintainable at some point, so it's better to avoid do blocks with current semantic at all. I hope at someday we will have better constructs for expression-oriented style, such as pattern matching, but do is probably a step in a wrong way. And yep, do mixed with async would be super confusing. Thx again for pointing on a good explanation :)