Description
On 64a4921, @zloirock left this comment:
this fallback will not properly work with sync iterators.
await Array.fromAsync([Promise.resolve(1), 2, Promise.resolve(3)]); // => [Promise.resolve(1), 2, Promise.resolve(3)]Something like that could be simpler.
Let usingAsyncIterator be ? GetMethod(asyncItems, @@asyncIterator). Let usingIterator be undefined. If usingAsyncIterator is undefined, Let usingIterator be ? GetMethod(asyncItems, @@Iterator). If usingIterator is undefined, Let usingIterator be ? %Array.prototype.values%. ... If usingAsyncIterator is not undefined, Let iteratorRecord be ? GetIterator(asyncItems, async, usingAsyncIterator). Else, Let syncIteratorRecord be ? GetIterator(asyncItems, sync, usingIterator). Let iteratorRecord be ? CreateAsyncFromSyncIterator(syncIteratorRecord).
The problem is that the current specification will not properly await
each value yielded from a synchronous iterator. (We do want await
to be called on each value from a synchronous iterator—this is what for await
does.)
This problem is due to how the spec currently incorrectly creates an synchronous iterator. Step 3.e.iii assigns iteratorRecord to GetIterator(asyncItems, async, usingAsyncOrSyncIterator), which results in a synchronous iterator that does not call await
on each of its yielded values. What we need to do is copy GetIterator when it is called with an async hint. We need to call CreateAsyncFromSyncIterator on the created sync iterator, which in turn will create an Async-from-Sync Iterator object, whose next
method will call await
on each of its values. (Thanks @bakkot for the help).
I will fix this later.
Activity
explainer/spec: Sync iterators and array-like objects
zloirock commentedon Sep 19, 2021
The same problem is with non-iterable array-like objects. The simplest solution above -)
js-choi commentedon Sep 24, 2021
I’m a little confused. How does the current algorithm not work with non-iterable array-like objects?
If asyncItems is a non-iterable array-like object, then GetMethod(asyncItems, @@asyncIterator) and GetMethod(asyncItems, @@iterator) would be both
undefined
, which makes usingAsyncOrSyncIteratorundefined
, which means step 3.e is skipped and step 4.f etc. are executed.zloirock commentedon Sep 24, 2021
The current algorithm doesn't await the value (async-from-sync iterator behavior) and the result of the callback.
js-choi commentedon Sep 24, 2021
Aha, that’s what you mean. I understand now—thank you for explaining. I will fix this when I can later.
[-]Sync iterator’s values are not awaited[/-][+]Sync iterator’s and array-like objects’ values are not awaited[/+]explainer/spec: Sync inputs must await each item
explainer/spec: Sync inputs must await each item
explainer/spec: Sync inputs must await each item
explainer/spec: Sync inputs must await each item
explainer/spec: Sync inputs must await each item
explainer/spec: Sync inputs must await each item (#11)