Можно ли сбросить генератор ECMAScript 6 в исходное состояние?
мой вопрос таков: учитывая предоставленный (очень простой) генератор, можно ли вернуть генератор в исходное состояние для использования снова?
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);
}
Я хотел бы иметь возможность передать итерацию в какую-то другую область, повторить ее, сделать некоторые другие вещи, а затем снова повторить ее позже в той же области.
6 ответов
Если ваше намерение состоит
в какую-то другую область, повторите ее, сделайте что-то еще, а затем снова повторите ее позже в той же области.
тогда единственное, что вы не должны пытаться сделать, это передать итератор, а не передать генератор:
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);
}
}
или просто сделайте итератор" round robin " и проверьте во время итерации
var generator = function*() {
while(true){
yield 1;
yield 2;
yield 3;
}
};
for( x in i ){
console.log(x);
if(x === 3){
break;
}
}
в этот момент Iterable потребляется.
что означает, что его внутренний [[GeneratorState]] является completed
.
есть ли метод для перемещения итерационного обратно в начальную точку только без повторного вызова generator ()
нет. Спец государств
как только генератор входит в состояние "завершено", он никогда не покидает его, и связанный с ним контекст выполнения никогда не возобновляется. Любое состояние исполнения связанный с генератором может быть отброшен в этот момент.
или, возможно, путем повторного вызова generator (), только с помощью prototype или методы конструктора, доступные в iterable object
нет. Хотя это явно не указано в спецификации, на iterable object чем [[GeneratorState]] и [[GeneratorContext]].
однако информативный "отношения объектов генератора" grapic гласит:
каждая функция генератора имеет связанный прототип, который не имеет свойства конструктора. Следовательно, экземпляр генератора не предоставляет доступ к его функции генератора.
Я хотел бы иметь возможность передать iterable в другую область
вместо этого передайте функцию генератора. Или что-то это дает новые экземпляры генератора.
Как только генератор выходит на
"completed"
состояние никогда не покидает его, и связанный с ним контекст выполнения никогда не возобновляется. Любое состояние выполнения, связанное с генератором, может быть отброшено в этот момент.
таким образом, нет способа сбросить его после его завершения. В этом тоже есть смысл. Мы называем его генератором, по какой-то причине:)
насколько я могу судить, это невозможно. Пер это полезная Вики и черновик версии ES6 на генераторах, как только вы вернулись из него (а не уступили), он помещает его в "closed"
состояние и нет способа переместить его обратно в "newborn"
состояние, в котором начинается новый генератор.
возможно, вам придется передать обратный вызов в другую область для создания нового генератора. В качестве обходного пути вы даже можете добавить этот обратный вызов как пользовательский метод на генераторе, который вы отправили в другую область, если хотите, и этот обратный вызов создаст новый генератор для другой области.
если вы думаете о том, как работают генераторы, они должны были бы выполнить с нуля, чтобы сбросить свое начальное состояние, и просто нет причин поддерживать это. Это было бы analagous спросить, почему вы не можете просто повторно выполнить конструктор на существующем объекте и ожидать, что девственный объект в том же объекте. Пока это все технически выполнимо, это волосато, чтобы сделать работу правильной, и на самом деле нет причин ее поддерживать. Если вам нужен девственный объект, просто создайте новый. То же самое с генератором.
Это немного хак, но любопытная вещь, чтобы рассмотреть. Можно сделать генератор, который будет повторяться. Предположим, ваш генератор работает следующим образом:--9-->
var generator = function*() {
while (true) {
yield 1;
yield 2;
yield 3;
yield null;
}
};
var iterable = generator();
for (let x of iterable) {
if (x === null) break;
console.log(x);
}
// generator is now in a state ready to repeat again
Я легко вижу, как это может быть анти-шаблон, хотя, потому что, если вы когда-нибудь это сделаете это:
for (let x of iterable) {
console.log(x);
}
у вас будет бесконечный цикл, поэтому его нужно будет использовать с большой осторожностью. FYI, выше wiki показывает примеры бесконечной последовательности Фибоначчи, поэтому, безусловно, рассматривается бесконечный генератор.
вы также можете сбросить свой генератор на итерацию следующим образом:
let iterable = generator();
function* generator(){
yield 1;
yield 2;
yield 3;
iterable = generator();
}
for (let x of iterable) {
console.log(x);
}
//Now the generator has reset the iterable and the iterable is ready to go again.
for (let x of iterable) {
console.log(x);
}
Я лично не знаю плюсов и минусов этого. Просто это работает так, как вы ожидаете, переназначая итерацию каждый раз, когда генератор заканчивается.
EDIT: с большим знанием того, как эта работа я бы рекомендовал просто использовать генератор, как Azder показал:
const generator = function*(){
yield 1;
yield 2;
yield 3;
}
for (let x of generator()) {
console.log(x);
}
for (let x of generator()) {
console.log(x);
}
версия, которую я рекомендовал, не позволит вам выполнить итераций, если он когда-либо терпит неудачу... Например, если вы ждали одного url-адреса для вызова другого. Если первый url-адрес не удается, вам придется обновить приложение, прежде чем он сможет попробовать этот первый выход снова.
всякий раз, когда вам нужно "сбросить" итерацию, просто выбросьте старый и сделайте новый.
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);
}