Synchronous exceptions thrown from complex expressions create abandoned promises. Solutions?

Let me give you my actual use case rather than the simplified and contrived ones I've shown so far:

async function compareApiImplementations(parameters) {
  return compareResults(...await Promise.all([
    newImplementation(parameters),
    oldImplementation(adaptParametersToOldImplementation(parameters))
  ]));
}

Here, newImplementation() and oldImplementation() are async functions of a value argument (property bag to be encoded into the URL of a REST service), compareResults() and adaptParametersToOldImplementation() are regular sync functions. Due to GIGO issues (implementation differences, essentially) adaptParametersToOldImplementation() may throw unexpectedly.

I do disagree with the position that unhandled rejections are harmless, btw. They are no more harmless than uncaught exceptions from a detached async context (like a timer tick handler). It is just that Promise.all() makes a design choice to ignore all rejections but the first one propagated; we can easily write an alternative API that would both propagate the result of the first rejected promise and report all subsequent rejections -- or successful resolutions! -- through a different channel, e.g. an event stream. Promises abandoned by an incomplete evaluation of the expression are fundamentally different as the programmer has no recourse in the matter.

PS. Sorry for belated editing, I almost missed my own point :-)

1 Like