proposal-async-do-expressions icon indicating copy to clipboard operation
proposal-async-do-expressions copied to clipboard

Use case of functions which return promise but have sync error handling

Open hax opened this issue 4 years ago • 4 comments

This is not an issue, but provide an use case of the proposal which can be add to readme.

Async functions always return a promise, if there is any error occured, the promise will be rejected. But in many cases, programmers may want sync error handling (for example, report illegal arguments immediately).

async function f(x) {
  if (x == null) throw new TypeError()
  ...
}

f() // a rejected promise

With async do, we can write:

function f(x) {
  if (x == null) throw new TypeError()
  return async do {
    ...
  }
}

f() // throw

hax avatar Mar 04 '21 15:03 hax

That would make the f function have what's referred to as "zalgo" behavior - in other words, that it is badly designed. Something should be always async, or never async.

See:

  • https://blog.izs.me/2013/08/designing-apis-for-asynchrony
  • https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/

Thus, I don't think this is a "use case" we should be documenting, since that might be seen as tacit encouragement of this antipattern.

ljharb avatar Mar 04 '21 15:03 ljharb

As I understand, "zalgo" means you should not sometime return promise sometime not, but throw errors for preconditions is not the case. Actually built-in promise methods also have that: if then is applied on non-promise object, typeerror will be thrown immediately.

hax avatar Mar 04 '21 15:03 hax

It’s the same thing - it’s the reason that async functions can never synchronously throw, even from default arguments. A synchronous throw is just as bad as a synchronous return from a function that can return a Promise.

Promise.then is not a violation of this because it’s not capable of making a Promise when its receiver is not one.

ljharb avatar Mar 04 '21 15:03 ljharb

Note https://blog.izs.me/2013/08/designing-apis-for-asynchrony actually have an example of throwing synchronously. And node.js callback-based api have many such usage.

Theoretically there are two types of errors, one is like return value in special form, these errors normally need to be deal with by try catch --- these errors should be keep async, another is just preconditions failure which means the program is broken and normally there is no way to recover and the only thing can do is exit gracefully. So throw such errors synchronously is not a big deal.

hax avatar Mar 04 '21 16:03 hax