03:17
<jschoi>
Is there a particular reason why Array.from (https://tc39.es/ecma262/#sec-cma262/#sec-call) seems to call CloseIterator if an error occurs when setting A’s properties, when there are too many items, and when mapfn throws an error—but not when IteratorStep results in an abrupt completion nor when the iterator depletes its items?
04:12
<bakkot>
we don't close the iterator when an error occurs in the iterator itself, because the iterator is broken
04:12
<bakkot>
and we don't close iterators when they are depleted in general
04:13
<bakkot>
(the assumption is that it does its own cleanup before returning {done: true})
04:13
<bakkot>
we only call IteratorClose when we need to close an iterator because we can no longer consume it for reasons of our own
05:19
<jschoi>
I see. I also see you’ve posted https://github.com/tc39/rationale/issues/2. Thank you for both that and the explanation.
06:13
<jschoi>
https://github.com/tc39/proposal-array-from-async/issues/16#issuecomment-995453541
As far as I can tell, there is no way to capture all possible rejections from a sync iterable’s yielded promises, while still maintaining for await semantics. This is correct, right?
17:54
<Mathieu Hofman>
What does for await (const foo of iterableYieldingPromises) do in this case?
17:55
<Mathieu Hofman>
If I was to implement this in a polyfill, I'd setup a dummy .catch() on the next promise to avoid the unhandled error, but still yield the original promise later
17:56
<Mathieu Hofman>
It's a pretty common occurrence when parallelizing async operations
18:00
<Mathieu Hofman>
What does for await (const foo of iterableYieldingPromises) do in this case?
My bad I didn't read the OP. It goes unhandled! Wondering if it's something we should fix in the language. I suppose the problem is that if the loop body throws in an error during processing of the second element, then the IteratorClose has no way to report the error. Maybe recreating a promise resolved with the rejection to trigger a future unhandled error would work
19:39
<Mathieu Hofman>
Ugh I wasn't awake, the OP example is flawed, and Async-from-Sync Iterator objects behave correctly
21:30
<Mathieu Hofman>

Actually follow up on Async-from-Sync Iterator objects / for await of. The following IteratorClose behavior seem surprising to me:

function * gen() {
  try {
    yield Promise.resolve(1);
    yield Promise.reject(2);
  } finally {
    console.log('iter cleanup');
  }
}

for of behaves as expected:


for (const i of  gen()) {
console.log(await i);
}
// 1 "iter cleanup" (Uncaught 2)

for await of however doesn't close the iterator


for await (const i of  gen()) {
console.log(i);
}
// 1 (Uncaught 2)
21:52
<Ashley Claymore 🤒>
At least the solution for this particular example is a one keyword change to async function * gen() {
21:52
<Ashley Claymore 🤒>
though I was surprised there was a difference
21:53
<Mathieu Hofman>
sure, but then that iterator is async and can no longer be used with sync iteration
21:54
<Ashley Claymore 🤒>
good point :)
21:55
<Ashley Claymore 🤒>
Would it be possible to change this, or working-as-intended/too-late-to-change
21:58
<Mathieu Hofman>
I'm not sure, there is other behavior with IteratorClose I find strange, like the swallowing of errors in return if the iterator was closed by a for-of loop that threw, which is kinda the opposite of finally errors shadowing try errors
22:04
<Mathieu Hofman>
Wondering if something can be done in step 10 of AsyncFromSyncIteratorContinuation
22:06
<Mathieu Hofman>
like close the sync iterable on wrapper value rejection since rejecting the next call will cause consumers of the async iterable to bail from ever touching the async iterable again