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

**URL:** <https://es.discourse.group/t/synchronous-exceptions-thrown-from-complex-expressions-create-abandoned-promises-solutions/663>\
**Category:** 💡 Ideas\
**Created:** [February 24, 2021, 5:02am UTC](https://es.discourse.group/t/synchronous-exceptions-thrown-from-complex-expressions-create-abandoned-promises-solutions/663 "2021-02-24T05:02:05Z")\
**Posts on this page:** 14\
**Page:** 3

<div class="post-metadata">

**Author:** ![bergus](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/bergus/32/152_2.png) [@bergus](https://es.discourse.group/u/bergus)\
**Post date:** [March 2, 2021, 11:23pm UTC](https://es.discourse.group/t/synchronous-exceptions-thrown-from-complex-expressions-create-abandoned-promises-solutions/663/41 "2021-03-02T23:23:27Z")

</div>

> [@MaxMotovilov](#):
>
> Let's assume we extend await to optionally support a list of concurrent asynchronous expressions. Note that this is emphatically **not** the same as "accept a list of promises"

I just realised that `Promise.all` does not take a list of promises. It takes an _iterable_ of promises. Which means it is possible already to write

```javascript
try {
  const [a, b, c] = await Promise.all(function*() {
    yield new Promise((_, reject) => setTimeout(reject, 1, "first"));
    yield Promise.reject("second");
    throw new Error("third");
  }());
} catch(e) {
  console.error(e);
}

```

which does not cause an unhandled rejection. I have to admit it's totally ugly, but it seems to have exactly the semantics you asked for?

---

<div class="post-metadata">

**Author:** ![bergus](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/bergus/32/152_2.png) [@bergus](https://es.discourse.group/u/bergus)\
**Post date:** [March 2, 2021, 11:33pm UTC](https://es.discourse.group/t/synchronous-exceptions-thrown-from-complex-expressions-create-abandoned-promises-solutions/663/42 "2021-03-02T23:33:18Z")

</div>

> [@theScottyJam](#):
>
> I'm at a loss as to how this could have been designed differently.

> [@MaxMotovilov](#):
>
> a more elaborate API that can implement custom strategies such as race-to-the-first-but-preserve-the-rest or collect-all-not-failed or what have you. If cancellation "backchannel" was added to promises, it could also make use of that as optimization

I'm a huge fan of the article [_Timeouts and cancellation for humans_](https://vorpus.org/blog/timeouts-and-cancellation-for-humans/) and the design laid out in it.  
It allows to create a scope in which tasks (asynchronous functions) can be spawned, and the scope basically doesn't exit until all tasks in it have completed (or were cancelled). But I don't think I should attempt to explain the concept in the here, go ahead and read the article! It's really worth it, even for people not working with Python.

---

<div class="post-metadata">

**Author:** ![claudiameadows](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/claudiameadows/32/126_2.png) [@claudiameadows](https://es.discourse.group/u/claudiameadows)\
**Post date:** [March 2, 2021, 11:52pm UTC](https://es.discourse.group/t/synchronous-exceptions-thrown-from-complex-expressions-create-abandoned-promises-solutions/663/43 "2021-03-02T23:52:14Z")

</div>

Not quite the same as the `Promise.all` case I'm citing where multiple promises reject. In that case, all rejections _have_ handlers installed, but the handlers are themselves collected or something and so I get unhandled rejection errors despite that. Need to test this a little deeper, though.

---

<div class="post-metadata">

**Author:** ![MaxMotovilov](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/maxmotovilov/32/648_2.png) [@MaxMotovilov](https://es.discourse.group/u/MaxMotovilov)\
**Post date:** [March 3, 2021, 2:32am UTC](https://es.discourse.group/t/synchronous-exceptions-thrown-from-complex-expressions-create-abandoned-promises-solutions/663/44 "2021-03-03T02:32:27Z")

</div>

It seems to work :-) -- I guess because Promise.all() attaches catch handlers synchronously as it consumes promises from the generator. So this is sort of how the "asynchronous comma" could be implemented by e.g. Babel -- but the syntax is, as you say, hardly workable.

---

<div class="post-metadata">

**Author:** ![MaxMotovilov](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/maxmotovilov/32/648_2.png) [@MaxMotovilov](https://es.discourse.group/u/MaxMotovilov)\
**Post date:** [March 3, 2021, 2:45am UTC](https://es.discourse.group/t/synchronous-exceptions-thrown-from-complex-expressions-create-abandoned-promises-solutions/663/45 "2021-03-03T02:45:28Z")

</div>

> [@bergus](#):
>
> article [_Timeouts and cancellation for humans_](https://vorpus.org/blog/timeouts-and-cancellation-for-humans/) and the design laid out in it

Nice design indeed, but seems to be reliant on the ole' "everyone uses this facility" rule? So something like this can only be incorporated at a fundamental level rather than used incrementally?

Also, I admit I speed-read the article so may have missed a few -- or a lot -- of ideas... but offhand I don't see how this cancellation mechanism can be readily applied to the Promise.all() problem -- cancel all underlying asynchronous operations whose promises have not yet settled at the point where the first one failed?

---

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [March 3, 2021, 3:17am UTC](https://es.discourse.group/t/synchronous-exceptions-thrown-from-complex-expressions-create-abandoned-promises-solutions/663/46 "2021-03-03T03:17:02Z")

</div>

Alright, I think we're going somewhere with your `await[]` syntax :) - I have a more clear idea of what we're tackling now.

What we're looking for is a syntax that can be used to ensure no uncaught promise errors will slip through between the time that you make the promise and the time you await.

The newly proposed `array[]` syntax would make great strides towards that direction, but I do see a couple of limitations to it. For these bullet points, I'll refer to each comma-separated expression in your await list as a promised expression.

- What do you do if one of the promised expressions depends on the result of another promised expression to evaluate?
- How would you handle complicated result-handling logic? i.e. how might you translate something like this to this new syntax, in an error-safe way? await Promise.all([\<expression 1 that might throw\>, Promise.race([\<expression 2 that might throw\>, \<expression 3\>])])

I think both of these scenarios could be resolved if we could name each promised expression. Here's an alternative syntax that allows naming the expressions by just binding each expression to a variable.

The following "promise declaration" syntax works as follows:

```javascript
// The following statement
async const promisedValue = <expression>
// is equivalent to any of these that have already been brought up in this thread.
const promisedValue = promise <expression>
const promisedValue = async do { <expression> }
const promisedValue = Promise.resolve().then(() => <expression>)

```

The beauty comes is when you chain the declarations:

```javascript
async const
  promisedValue1 = getValue1(),
  promisedValue2 = getValue2(ThisMightThrow(), await promisedValue1),
  promisedValue3 = getValue3(...await Promise.all([promisedValue1, promisedValue2])),
  promisedResults = await Promise.all([promisedValue1, promisedValue2, promisedValue3])

const [value1, value2, value3] = await promisedResults

```

This sort of makes a promise pipeline, where it's very easy to construct new promises that depend on the results of earlier ones. One important thing to note is that no errors can be made within that `async const` declaration - any errors would get converted to rejected promises. Thus, as long as this syntax is used properly, it's very easy to ensure that we're not creating a promise then throwing an error before the promise is awaited. The equivalent to the above example would probably be something like this:

```javascript
const getValue2Param = ThisMightThrow()
const promisedValue1 = getValue1()
const promisedValue2 = promisedValue1.then(value1 => getValue2(getValue2Param, value1))
const [value1, value2, value3] = await Promise.all([
  promisedValue1,
  promisedValue2,
  Promise.all([promisedValue1, promisedValue2]).then(res => getValue3(...res))
])

```

Notice how the ordering of statements in this rewrite is much more fragile. In this version, I had to move the function call to `thisMightThrow()` above the location where the first promise was made. The reasons for moving it above aren't immediately apparent by looking at this code, and it would be so easy for future maintainers to move it below the first promise, creating a bug. This doesn't need to happen with this promise declaration syntax, because the errors are automatically swallowed up and turned into rejected promises, so thisMightThrow() can just be called at the place where its value gets used.

Here are some more examples based on previous code snippets from this thread. For clarity, I'm putting a "$" at the end of any variable that holds a promise.

```javascript
async fetchUserInfo(params) {}
  try {
    async const
      value1$ = await getValue1(),
      value2$ = await getValue2(params),
      value3$ = await getValue3(await value1$),
      userInfo$ = do {
        const [value1, value2, value3] = await Promise.all([value1$, value2$, value3$])
        { value1, value2, value3 }
      }

    return await userInfo$
  } catch (err) {
    if (err.type === NOT_LOGGED_IN) return null
    throw err
  }
}

```

```javascript
async function compareApiImplementations(parameters) {
  async const
    result1$ = newImplementation(parameters),
    result2$ = oldImplementation(adaptParametersToOldImplementation(parameters)),
    comparison$ = compareResults(...await Promise.all([result1$, result2$])
  return comparison$
}

```

This example shows how one might implement the following snippet from earlier, in an error safe way: `await Promise.all([<expression 1 that might throw>, Promise.race([<expression 2 that might throw>, <expression 3>])])`

```javascript
async const
  part1 = <expression 1 that might throw>,
  part2 = <expression 2 that might throw>,
  result = await Promise.all([part1, Promise.race([part2, <expression 3>])])

return await result

```

And this example shows the similarities this has with `await[]`:

```javascript
// The following example with await[] ...
const [res1, res2] = await[
  <expression1>,
  <expression2>
].all()

// ... would be equivalent to this:
async const
  res1$ = <expression1>,
  res2$ = <expression2>

const [res1, res2] = await Promise.all([res1$, res2$])

```

There are certainly some flaws I can think of with this concept, but I think it's at least a step in the right direction for solving @MaxMotovilov's issue.

---

<div class="post-metadata">

**Author:** ![MaxMotovilov](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/maxmotovilov/32/648_2.png) [@MaxMotovilov](https://es.discourse.group/u/MaxMotovilov)\
**Post date:** [March 3, 2021, 4:02am UTC](https://es.discourse.group/t/synchronous-exceptions-thrown-from-complex-expressions-create-abandoned-promises-solutions/663/47 "2021-03-03T04:02:46Z")

</div>

> [@theScottyJam](#):
>
> What do you do if one of the promised expressions depends on the result of another promised expression to evaluate?

Let's parse this: call them A and B; "A depends on B" I interpret as B is a sub-expression of A. After all, that's how traditional expressions work: in 2 \* (3 + 4), 2 \* () depends on (3+4). In case of async expressions, "A depends on the result of B" must mean "await B" is a sub-expression of A. I don't think this even falls under the same use case.

> [@theScottyJam](#):
>
> how might you translate something like this to this new syntax, in an error-safe way? await Promise.all([\<expression 1 that might throw\>, Promise.race([\<expression 2 that might throw\>, \<expression 3\>])])

```javascript
await[expr1, await[ expr2, expr3].race() ].all()

```

Seems straightforward to me.

Being rather allergic to throwaway name bindings, I fail to see the beauty of the "async declaration", but I think it is, indeed, equivalent to my original "unary operator". Depending on the context, one is either more or less verbose than the other: if you really need the bindings, your syntax saves on not having to repeat the "async" qualifier in front of the declaration; if you don't need the bindings at all, my syntax wins by omitting the unnecessary names.

The trick in all cases -- including await syntax -- is having a recognizable syntactic context where any evaluation result including a synchronous exception is converted to a promise. Async functions make that guarantee at the scope of a function; I'd like to have it at the scope of a [sub-]expression.

BTW yet another variation of await -- let me call it async just to keep the two distinct -- could simply make this guarantee for a list of sub-expressions and return an array of promises. This would lead to simpler semantics and an easier fit with the existing facilities at a price of, again, verbosity :-(

```javascript
await Promise.all( async[foo(), bar()] )

```

We can also explore the idea @bergus described in [Synchronous exceptions thrown from complex expressions create abandoned promises. Solutions? - #41 by bergus](https://es.discourse.group/t/synchronous-exceptions-thrown-from-complex-expressions-create-abandoned-promises-solutions/663/41). What it amounts to is a generator-based interface where the consumer of the sequence has a chance to perform [synchronous] actions on each element before the next element will be evaluated. Missing is a simple syntax that would allow construction of sequences in that manner -- a form of not-quite-iterator comprehension from Python 3. I am going to take advantage of the fact that JS does not have an unary "\*" operator (oh the fun I used to have in C++ overloading it!):

```javascript
await Promise.all( *[foo(), bar()] );

```

And now I posit the semantics of "\*[" list-of-expressions "]" as simply:

```javascript
(function*(){ yield expression-1; ... yield expression-n; })();

```

It has nothing to do with async at all -- just a way to construct generators in-line; a "generator comma" instead of an "async comma". This means that Promise.all() and other possible async combinators have to all be tricky enough to consume each promise atomically but that's a worry for another day. It is sufficient that we _can_ guarantee sub-expression isolation that way.

I guess this is now my favorite option, hah!

---

<div class="post-metadata">

**Author:** ![MaxMotovilov](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/maxmotovilov/32/648_2.png) [@MaxMotovilov](https://es.discourse.group/u/MaxMotovilov)\
**Post date:** [March 3, 2021, 5:31am UTC](https://es.discourse.group/t/synchronous-exceptions-thrown-from-complex-expressions-create-abandoned-promises-solutions/663/48 "2021-03-03T05:31:41Z")

</div>

Follow-up: I can't seem to find an existing proposal for a generator literal -- because this is what it is. Given that it solves a real problem with async expressions, and that the Promise.all()/Promise.race() APIs seem custom-made for such a thing, perhaps there should be one?

In its simplest form, \*[expression\_1, ... expression\_N] is evaluated as

```javascript
(function*() {
  yield expression_1;
  ...
  yield expression_N;
})()

```

As there's no way to inject local names in the closure created by the function\*() wrapper, I fail to see any possible edge cases. Should be really simple to implement with a Babel plugin (I may try doing just that shortly, if I find some time).

Now that I'm in a celebratory mood, I feel ready for some mischief. How about supporting the equivalent of yield\* in this syntax? After all, it's just the same as ... spread operator in an array literal, right? So let's say "\*[...expression]" -- this time "..." is used verbatim -- is an equivalent of:

```javascript
(function*() {
  yield* expression;
})()

```

So far so good, right? Still nothing breaks, not really any new syntax introduced as ... already works inside both [] and {}, so why not here.

Digging further. When we say:

```javascript
const seq = *[expr1, expr2, ...expr];

```

at what point is "seq" bound? The question is **not** trivial because none of expr1, expr2 or expr are even evaluated until someone starts iterating over seq! The natural answer is that seq is bound to the generator roughly speaking at "= \*[". Fair enough.

Here comes the prank I was carefully preparing:

```javascript
let i = 0;
const cardinals = *[++i, ...cardinals];

```

I give you... infinite recurrent sequences! Just what I always wanted for my birthday!

```javascript
let a=0, b=1;
const fib = *[a+=b, b+=a, ...fib];

```

---

<div class="post-metadata">

**Author:** ![aclaymore](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/aclaymore/32/501_2.png) [@aclaymore](https://es.discourse.group/u/aclaymore)\
**Post date:** [March 3, 2021, 8:51am UTC](https://es.discourse.group/t/synchronous-exceptions-thrown-from-complex-expressions-create-abandoned-promises-solutions/663/49 "2021-03-03T08:51:00Z")

</div>

Related: [GitHub - tc39/proposal-await.ops: Introduce await.all / await.race / await.allSettled / await.any to simplify the usage of Promises](https://github.com/tc39/proposal-await.ops) which adds `await.all exp` syntax

---

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [March 3, 2021, 3:04pm UTC](https://es.discourse.group/t/synchronous-exceptions-thrown-from-complex-expressions-create-abandoned-promises-solutions/663/50 "2021-03-03T15:04:50Z")

</div>

> [@MaxMotovilov](#):
>
> ```javascript
> await[expr1, await[expr2, expr3].race() ].all()
> 
> ```
> 
> Seems straightforward to me.

Ah - I had wrongly presumed that the goal was to put all of the async expressions into a single `await[]`, and as long as we do that, we can be sure no errors happen between the time a promise is made, and when it gets used. But, I see now that its perfectly safe to nest them, or to assign the result of one await to a variable and immidietally use it in another.

We can just ignore my whole `async const` thing - there were a number of things I didn't like about it anyways. I was just trying to find a way to do it all in one syntax chunk. You'll probably get better luck with your `*[]` syntax.

---

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [March 3, 2021, 4:20pm UTC](https://es.discourse.group/t/synchronous-exceptions-thrown-from-complex-expressions-create-abandoned-promises-solutions/663/51 "2021-03-03T16:20:07Z")

</div>

I guess the other options would be looking at @aclaymore's reference to this other proposal and seeing about altering it slightly.

So, instead of `await.all <array>`, it uses `await.all[<lazy-evaluated expression 1, lazy-evaluated expression 2>]`

This would make these await.\* syntax additions do something other than just provide a shortand for Promise.\* functions. And would bring it pretty close to your `await[]` idea.

---

<div class="post-metadata">

**Author:** ![MaxMotovilov](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/maxmotovilov/32/648_2.png) [@MaxMotovilov](https://es.discourse.group/u/MaxMotovilov)\
**Post date:** [March 3, 2021, 5:04pm UTC](https://es.discourse.group/t/synchronous-exceptions-thrown-from-complex-expressions-create-abandoned-promises-solutions/663/52 "2021-03-03T17:04:41Z")

</div>

Honestly, I now like the generator literal a lot more. It is a simpler -- almost trivial, pure syntax! -- addition, it generalizes into other unrelated capabilities such as by-name parameters and it's far past time for Javascript to start catching up with Python in iterator-based programming.

Trying to find a time window for Babel implementation and a more detailed writeup, so that I can submit this proposal on its own merits.

---

<div class="post-metadata">

**Author:** ![claudiameadows](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/claudiameadows/32/126_2.png) [@claudiameadows](https://es.discourse.group/u/claudiameadows)\
**Post date:** [March 28, 2021, 5:19pm UTC](https://es.discourse.group/t/synchronous-exceptions-thrown-from-complex-expressions-create-abandoned-promises-solutions/663/53 "2021-03-28T17:19:58Z")

</div>

I've got a better solution here: [Proposal + seeking champion: Composable promise concurrency management](https://es.discourse.group/t/proposal-seeking-champion-composable-promise-concurrency-management/713)

---

<div class="post-metadata">

**Author:** ![MaxMotovilov](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/maxmotovilov/32/648_2.png) [@MaxMotovilov](https://es.discourse.group/u/MaxMotovilov)\
**Post date:** [March 28, 2021, 6:40pm UTC](https://es.discourse.group/t/synchronous-exceptions-thrown-from-complex-expressions-create-abandoned-promises-solutions/663/54 "2021-03-28T18:40:38Z")

</div>

Read through - while I see the advantages of the proposal as regards the patterns outlined in it, I fail to see how it applies to this thread. Granted an explicit async wrapper required by your API, even this naive boilerplate solves the problem:

```javascript
Promise.all([
  foo(), // The async function call
  (async () => bar(baz()))() // Sync call followed by async call, wrapped
])

```

Verbose, but no more so than it'll have to be to use `Promise.scheduleAndRun()`, no?

[Previous page](https://es.discourse.group/t/synchronous-exceptions-thrown-from-complex-expressions-create-abandoned-promises-solutions/663.md?page=2)
