You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
GetIterator(obj, ASYNC) returns an Iterator Record with a [[NextMethod]] that is pulled from the user-supplied object. The next method hopefully returns a Promise, but this requirement is not enforced. Because it is not enforced, specs that convert values to async iterators this way must take care to wrap the resulting value in a Promise. This is standard practice; the Streams Standard does this, and so do the semantics of for await loops: specifically, the head evaluation semantics grab an async iterator record, and then step 6 of the body evaluation gets the next value and unconditionally Await()s it. Await()first wraps the value in a Promise and awaits it, which is necessary in case the value returned from the author's async iterable's next() method is not a Promise.
In other words, the consumer of an async iterable is responsible for wrapping all next() values in a Promise, in case the code author did not do this. This is understandable, but a little annoying I guess, since responsibility is pushed to the consumer when ECMAScript itself could take care of this.
In fact, ECMAScript does take care of this (i.e., ensuring that all next() values are Promises) but only when GetIterator(obj, ASYNC) falls back to the @@iterator implementation (i.e., when @@asyncIterator is not present). In this case and this case only, the fallback prose doesn't just directly use the sync iterator Record for its next() values; instead, it delegates to CreateAsyncFromSyncIterator(), which creates an internal %AsyncFromSyncIteratorPrototype% object whose next() method is guaranteed to return a Promise that resolves to the underlying [[SyncIteratorRecord]]'s actual next value (which should be an Iterator Result).
This automatic Promise-wrapping is quite nice, but it's strange that we only do it for the least kind of async iterable, i.e., sync iterables. Since we have this automatic Promise-wrapping semantics sometimes, it'd be nice if we could extend it to all converted async iterables, so that consumers of GetIterator(obj, ASYNC) could always guarantee that the result of IteratorNext() is a Promise.
If we don't, then since consumers of async iterables are anyways trained to do the wrapping themselves, maybe we can just get rid of the CreateAsyncFromSyncIterator() usage in the sync fallback case. After all, there's no need for [[NextMethod]] to always return a Promise, since consumers can't rely on this in general.
Thoughts?
The text was updated successfully, but these errors were encountered:
GetIterator(obj, ASYNC)
returns an Iterator Record with a[[NextMethod]]
that is pulled from the user-supplied object. The next method hopefully returns a Promise, but this requirement is not enforced. Because it is not enforced, specs that convert values to async iterators this way must take care to wrap the resulting value in a Promise. This is standard practice; the Streams Standard does this, and so do the semantics of for await loops: specifically, the head evaluation semantics grab an async iterator record, and then step 6 of the body evaluation gets the next value and unconditionallyAwait()
s it.Await()
first wraps the value in a Promise and awaits it, which is necessary in case the value returned from the author's async iterable'snext()
method is not a Promise.In other words, the consumer of an async iterable is responsible for wrapping all
next()
values in a Promise, in case the code author did not do this. This is understandable, but a little annoying I guess, since responsibility is pushed to the consumer when ECMAScript itself could take care of this.In fact, ECMAScript does take care of this (i.e., ensuring that all
next()
values are Promises) but only whenGetIterator(obj, ASYNC)
falls back to the@@iterator
implementation (i.e., when@@asyncIterator
is not present). In this case and this case only, the fallback prose doesn't just directly use the sync iterator Record for itsnext()
values; instead, it delegates toCreateAsyncFromSyncIterator()
, which creates an internal%AsyncFromSyncIteratorPrototype%
object whosenext()
method is guaranteed to return a Promise that resolves to the underlying[[SyncIteratorRecord]]
's actual next value (which should be an Iterator Result).This automatic Promise-wrapping is quite nice, but it's strange that we only do it for the least kind of async iterable, i.e., sync iterables. Since we have this automatic Promise-wrapping semantics sometimes, it'd be nice if we could extend it to all converted async iterables, so that consumers of
GetIterator(obj, ASYNC)
could always guarantee that the result ofIteratorNext()
is a Promise.If we don't, then since consumers of async iterables are anyways trained to do the wrapping themselves, maybe we can just get rid of the
CreateAsyncFromSyncIterator()
usage in the sync fallback case. After all, there's no need for[[NextMethod]]
to always return a Promise, since consumers can't rely on this in general.Thoughts?
The text was updated successfully, but these errors were encountered: