Is it possible to reset an ECMAScript 6 generator to its initial state?

Given the provided (very simple) generator, is it possible to return the generator back to its original state to use again?

var generator = function*() {
    yield 1;
    yield 2;
    yield 3;
};

var iterable = generator();

for (let x of iterable) {
    console.log(x);
}

// At this point, iterable is consumed.
// Is there a method for moving iterable back
// to the start point by only without re-calling generator(),
// (or possibly by re-calling generator(), only by using prototype 
//  or constructor methods available within the iterable object)
// so the following code would work again?

for (let x of iterable) {
    console.log(x);
}

I would like to be able to pass the iterable off to some other scope, iterate over it, do some other stuff, then be able to iterate over it again later on in that same scope.


Solution 1:

If your intention is

to some other scope, iterate over it, do some other stuff, then be able to iterate over it again later on in that same scope.

Then the only thing you shouldn't try doing is passing the iterator, instead pass the generator:

var generator = function*() {
    yield 1;
    yield 2;
    yield 3;
};

var user = function(generator){

    for (let x of generator()) {
        console.log(x);
    }

    for (let x of generator()) {
        console.log(x);
    }
}

Or just make a "round robin" iterator and check while iterating

var generator = function*() {
    while(true){
        yield 1;
        yield 2;
        yield 3;
    }
};

for( x in i ){
    console.log(x);
    if(x === 3){
        break;
    }
}

Solution 2:

At this point, iterable is consumed.

Which means its internal [[GeneratorState]] is completed.

Is there a method for moving iterable back to the start point by only without re-calling generator()

No. The spec states

Once a generator enters the "completed" state it never leaves it and its associated execution context is never resumed. Any execution state associated with generator can be discard at this point.

or possibly by re-calling generator(), only by using prototype or constructor methods available within the iterable object

No. While not explicitly stated in the spec, there are no more instance-specific properties available on the iterable object than [[GeneratorState]] and [[GeneratorContext]].

However, the informative "Generator Object Relationships" grapic states:

Each Generator Function has an associated prototype that does not have a constructor property. Hence a generator instance does not expose access to its generator function.

I would like to be able to pass the iterable off to some other scope

Pass the generator function instead. Or something that yields new generator instances.

Solution 3:

Whenever you need to "reset" an iterable, just toss the old one away and make a new one.

var generator = function*() {
    yield 1;
    yield 2;
    yield 3;
};
const makeIterable = () => generator()

for (let x of makeIterable()) {
    console.log(x);
}

// At this point, iterable is consumed.
// Is there a method for moving iterable back
// to the start point by only without re-calling generator(),
// (or possibly by re-calling generator(), only by using prototype 
//  or constructor methods available within the iterable object)
// so the following code would work again?

for (let x of makeIterable()) {
    console.log(x);
}

Solution 4:

As per the draft version of ES6,

Once a generator enters the "completed" state it never leaves it and its associated execution context is never resumed. Any execution state associated with generator can be discard at this point.

So, there is no way to reset it once it is completed. It also makes sense to be so. We call it a generator, for a reason :)