Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this async generator cause the JavaScript runtime to hang?

Tags:

javascript

The following JavaScript causes the runtime to hang on Chrome (v80.0.3987.116) and Firefox (v72.0.2) on OSX 10.15.2.

Why?

Note that I am marking the iterator function as async.

const iterable = {
    async *[Symbol.iterator]() {
        yield 'one'
    }
}

console.log([...iterable])
like image 341
Ben Aston Avatar asked Feb 23 '20 19:02

Ben Aston


Video Answer


2 Answers

Because now your [Symbol.iterator] method no longer returns an Iterator, it does return an AsyncIterator. That's still an object with a .next() method, so the spread syntax trying to iterate it doesn't complain. But the calls to the .next() method do no longer return {value:…, done:true} objects, they always return a promise. These promise objects have no truthy done property, so your iterator never stops…

You can achieve the same result with

const iterable = {
    *[Symbol.iterator]() {
        while (true) {
            yield
        }
    }
}    
console.log([...iterable])

or

const iterable = {
    [Symbol.iterator]() {
        return {
            next() {
                return {};
            }
        }
    }
}
console.log([...iterable])
like image 127
Bergi Avatar answered Oct 18 '22 01:10

Bergi


When you call console.log([...iterable]), it tells Javascript to get a generator from Symbol.iterator property on iterable to iterate over it. Where, Symbol.iterator is AsyncGenerator(because of async in front of it), rather not a regular Generator. Meaning that next function from that generator returns a Promise, but not an object with done and value values. So, js takes that returned Promise and looks for done property to be true to stop iteration, but returned Promise doesn't have this property, so the check fails and js keeps the iterations going.

The same result can be achieved in this way:

const iterable = {
  [Symbol.iterator]() {
    return {
      next() {
        return {} // <~ doesn't have done property - will cause infinite iteration
      }
    }
  }
}
console.log([...iterable])

Hope it helps <3

like image 3
Max Avatar answered Oct 18 '22 02:10

Max