I am trying to understand javascript's Symbol.asyncIterator and for await of. I wrote some simple code and it throws an error saying:
TypeError: undefined is not a function
on the line which tries to use for await (let x of a)
.
I could not understand the reason for it.
let a = {}
function test() {
for(let i=0; i < 10; i++) {
if(i > 5) {
return Promise.resolve(`Greater than 5: (${i})`)
}else {
return Promise.resolve(`Less than 5: (${i})`)
}
}
}
a[Symbol.asyncIterator] = test;
async function main() {
for await (let x of a) { // LINE THAT THROWS AN ERROR
console.log(x)
}
}
main()
.then(r => console.log(r))
.catch(err => console.log(err))
I create an empty object a
and insert a key Symbol.asyncIterator
on the same object and assign it a function named test
that returns a Promise
. Then I use for await of
loop to iterate over all the values that the function would return.
What am I doing incorrectly?
PS: I am on the Node version 10.13.0
and on the latest version of Chrome
To be a valid
asyncIterator
, yourtest
function must return an object with anext
method that returns a promise of a result object withvalue
anddone
properties. (Technically,value
is optional if its value would beundefined
anddone
is optional if its value would befalse
, but...)You can do that in a few ways:
You can do it completely manually (this doesn't try to get the right prototype):
You can do it half-manually writing a function that returns an object with an
async
next
method (still doesn't try to get the right prototype):Or you can just use an
async
generator function (easiest, and automatically gets the right prototype):About prototypes: All async iterators you get from the JavaScript runtime itself inherit from a prototype that provides the very basic feature of ensuring the iterator is also iterable (by having
Symbol.iterator
be a function returningthis
). There's no publicly-available identifer or property for that prototype, you have to jump through hoops to get it:Then you'd use that as the prototype of the object with the
next
method that you're returning: