Why does my generator become empty after being iterated through?

966 views Asked by At

I have a generator being returned to me by a function call from a library I'm using. I then pass this generator to a function which iterates through it and does a bunch of logic on each of the items. I then want to refer to this same generator after that function has been called. However, it seems the generator no longer has/generates any items. The code is along these lines:

let myGenerator = this.generatorFunc();
console.log(Array.from(myGenerator).length); //prints N which is specified elsewhere
this.iterateThroughGenerator(myGenerator);
console.log(Array.from(myGenerator).length); //now prints 0 when I need it to be N still

iterateThroughGenerator(generator) {
    for(let element of generator) {
        // do a bunch of stuff with element
    }
}
4

There are 4 answers

0
Nicholas Harder On

Once the generator function is completed, then you have to call this.getGeneratorFunc() to recreate the generator again. Also, when you do Array.from(myGenerator), it will complete that generator as well, so when you call this.iterateThroughGenerator(myGenerator) then nothing will occur because there are no elements being returned from the generator anymore. So you can either save the result of the generator into an array and reuse that array, or call this.getGeneratorFunc() three times for each time you want to get elements from it. In this specific example, I would do

 const generated = Array.from(this.getGeneratorFunc());
 console.log(generated.length);
 this.iteratedItems(generated);
 console.log(generated.length);

Check out this answer as well. Previous Answer
Id also read this.

0
Bergi On

Array.from() exhausts the generator (iterating it until the end), and iterating it further won't yield any more elements. next() calls will always return {value: undefined, done: true}.

To create a new generator that starts from the beginning again, you need to call the generatorFunc() again.

3
junvar On

That's how iterators work. Invoking a generator returns an iterator, which can be iterated once. This is the same in most other languages.

let generator = function* () {
  for (let i = 0; i < 3; i++) 
    yield i;
};

let iterator = generator();

console.log(Array.from(iterator)); // [1...3]
console.log(Array.from(iterator)); // []

console.log(Array.from(generator())); // [1..3]
console.log(Array.from(generator())); // [1..3]

0
Patrick Roberts On

Others have already explained why this is happening, but I'll recap anyway.

Generator functions return a generator object, which implements both the iterable protocol (a Symbol.iterator property) using a simple circular reference to itself, and the iterator protocol (a next() method) in order to statefully iterate through the control flow of its generator function.

To fix your problem, encapsulate the generator function call with an object that implements the iterable protocol by returning separate instances of your generator object, and you can use it the same way:

const iterable = { [Symbol.iterator]: () => this.generatorFunc() };

console.log(Array.from(iterable).length); //prints N which is specified elsewhere
this.iterateThroughGenerator(iterable);
console.log(Array.from(iterable).length); //still prints N

iterateThroughGenerator(iterable) {
    for(let element of iterable) {
        // do a bunch of stuff with element
    }
}