Почему мой генератор становится пустым после повторения?

У меня есть генератор, возвращаемый мне вызовом функции из библиотеки, которую я использую. Затем я передаю этот генератор функции, которая перебирает его и выполняет кучу логики для каждого из элементов. Затем я хочу обратиться к тому же генератору после вызова этой функции. Тем не менее, кажется, что генератор больше не имеет / генерирует какие-либо предметы. Код по этим направлениям:

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 ответа

Другие уже объяснили, почему это происходит, но я все равно напомню.

Функции генератора возвращают объект генератора, который реализует итеративный протокол (Symbol.iterator свойство), используя простую циклическую ссылку на себя, и протокол итератора (next() метод), чтобы выполнить итерацию по ходу потока управления его функции генератора.

Чтобы решить вашу проблему, инкапсулируйте вызов функции генератора с объектом, который реализует итеративный протокол, возвращая отдельные экземпляры вашего объекта генератора, и вы можете использовать его таким же образом:

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
    }
}

Вот так работают итераторы. Вызов генератора возвращает итератор, который можно повторить один раз. Это то же самое в большинстве других языков.

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]

Array.from() истощает генератор (повторяя его до конца), и повторяя его дальше, вы не получите больше элементов. next() звонки будут всегда возвращаться {value: undefined, done: true},

Чтобы создать новый генератор, который снова запускается с самого начала, вам нужно вызвать generatorFunc() очередной раз.

Как только функция генератора завершена, вы должны вызвать this.getGeneratorFunc() для повторного создания генератора. Кроме того, когда вы выполняете Array.from(myGenerator), он также завершает этот генератор, поэтому, когда вы вызываете this.iterateThroughGenerator (myGenerator), тогда ничего не произойдет, потому что больше нет элементов, возвращаемых из генератора. Таким образом, вы можете либо сохранить результат генератора в массив и повторно использовать этот массив, либо вызывать this.getGeneratorFunc() три раза каждый раз, когда вы хотите получить из него элементы. В этом конкретном примере я бы сделал

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

Проверьте этот ответ, а также. Предыдущий ответ
Я также читал это.

Другие вопросы по тегам