javascriptiteratorgeneratoryieldgarbage

Does each `yield` of a synchronous generator unavoidably allocate a fresh `{value, done}` object?


MDN says:

The yield keyword causes the call to the generator's next() method to return an IteratorResult object with two properties: value and done. The value property is the result of evaluating the yield expression, and done is false, indicating that the generator function has not fully completed.

I ran a test in Chrome 91.0.4472.77 and it appears to be a fresh object every single time. Which seems very wasteful if the processing is fine grained (high numbers of iterations, each with low computation). To avoid unpredictable throughput and GC jank, this is undesirable.

To avoid this, I can define an iterator function, where I can control (ensure) the reuse of the {value, done} object by each next() causing the property values to be modified in place, ie. there's no memory allocation for a new {value, done} object.

Am I missing something, or do generators have this inherent garbage producing nature? Which browsers are smart enough to not allocate a new {value, done} object if all I do is const {value, done} = generatorObject.next(); ie. I can't possibly gain a handle on the object, ie. no reason for the engine to allocate a fresh object?


Solution

  • It is a requirement of the ECMAScript specification for generators to allocate a new object for each yield, so all compliant JS engines have to do it.

    It is possible in theory for a JS engine to reuse a generator's result object if it can prove that the program's observable behavior would not change as a result of this optimization, such as when the only use of the generator is in a const {value, done} = generatorObject.next() statement. However, I am not aware of any engines (at least those that are used in popular web browsers) that do this. Optimizations like this are a very hard problem in JavaScript because of its dynamic nature.