2014-05-24 5 views
20

Meine Frage ist dies: Angesichts der bereitgestellten (sehr einfachen) Generator, ist es möglich, den Generator zurück in den ursprünglichen Zustand, um wieder zu verwenden?Ist es möglich, einen ECMAScript 6 Generator in den Ausgangszustand zurückzusetzen?

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

Ich mag wäre in der Lage sein, die iterable zu einem anderen Rahmen abgehen, durchlaufen sie, einige andere Sachen, dann in der Lage sein, über sie später im gleichen Umfang wieder zu wiederholen.

+0

nicht dem aktuellen Entwurf nach: https://people.mozilla.org/~jorendorff/es6-draft.html#sec-iterator-interface –

+2

Btw, sollte nicht ' für (sei x in iterierbar) 'sei' für (x von iterierbar)'? –

+0

Ja, Sie haben Recht - ich werde den Code aktualisieren. – dvlsg

Antwort

12

Wenn Ihre Absicht

zu einem anderen Bereich ist, über sie iterieren, einige andere Sachen tun, dann in der Lage sein, über sie wieder zu durchlaufen später in der gleiche Umfang.

Dann ist die einzige Sache, sollten Sie nicht versuchen zu tun, den Iterator ist vorbei, statt den Generator übergeben:

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

Oder einfach nur ein "Round-Robin" Iterator machen und überprüfen, während

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

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

Wie am besten kann ich sagen, dass das nicht möglich ist. Pro this useful wiki und die draft version of ES6 auf Generatoren, sobald Sie von ihm zurückgekehrt sind (anstatt nachgegeben), es setzt es in den "closed" Zustand und es gibt keine Möglichkeit, es wieder in den "newborn" Zustand, wie ein neuer Generator beginnt.

Möglicherweise müssen Sie einen Rückruf an Ihren anderen Bereich zum Erstellen eines neuen Generators übergeben. Als Umgehung könnten Sie diesen Rückruf sogar als benutzerdefinierte Methode für den Generator hinzufügen, den Sie an den anderen Bereich gesendet haben, wenn Sie möchten, und dieser Rückruf würde einen neuen Generator für den anderen Bereich erstellen.

Wenn Sie darüber nachdenken, wie Generatoren funktionieren, müssen sie von Grund auf neu ausführen, um ihren Ausgangszustand zurückzusetzen, und es gibt einfach keinen Grund, das zu unterstützen. Das wäre sinngemäß zu fragen, warum Sie nicht einfach den Konstruktor für ein existierendes Objekt erneut ausführen können und erwarten, dass ein neues Objekt in demselben Objekt vorhanden ist. Während alles technisch machbar ist, ist es haarig, die Arbeit richtig zu machen, und es gibt wirklich keinen Grund, es zu unterstützen. Wenn Sie ein jungfräuliches Objekt möchten, erstellen Sie einfach ein neues Objekt. Gleiches gilt für einen Generator.


Dies ist ein bisschen ein Hack, aber eine seltsame Sache zu betrachten. Du könntest einen Generator machen, der sich wiederholt. Angenommen, Ihr Generator wie folgt gearbeitet:

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 

Ich kann leicht sehen, wie könnte dies ein anti-Muster sein, obwohl, weil, wenn Sie jemals tun:

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

Sie eine Endlosschleife haben , also müsste es mit großer Sorgfalt verwendet werden. Zu Ihrer Information, das obige Wiki zeigt Beispiele einer unendlichen Fibonacci-Sequenz, so dass ein unendlicher Generator sicherlich in Erwägung gezogen wird.

+0

Das ist ein interessanter Gedanke. Ich glaube nicht, dass es in meiner Situation funktionieren wird, da ich keinen Zugang haben werde, um die ursprünglichen Generatoren zu modifizieren (ich erwäge, eine Bibliothek von mir zu erweitern, die Array-Manipulationen enthält, um auch mit Generatormanipulationen zu arbeiten). – dvlsg

+0

@dvlsg - Sie könnten einen Iterator mit einem eigenen Iterator umschließen, der eine '.restart()' Methode oder etwas ähnliches hat. Ihre '.restart()' Methode würde einfach einen neuen Iterator aus Ihrer Bibliothek erstellen und der nächste Aufruf von '.next()' auf Ihrem äußeren Iterator würde mit dem neuen internen Iterator beginnen. Hier gibt es viele Möglichkeiten, den Remote-Bereich neu zu starten. – jfriend00

+0

Ich denke, das ist die Route, die ich nehmen werde. Hoffnungsvoll. Ein Teil des Problems, auf das ich stoße, ist die Fähigkeit, Methoden von einem Generator zum nächsten zu verketten - ähnlich wie in C# Linq, wo man 'MyEnumerable.Where (x => x.id> 3) nennen könnte. Wählen Sie (x = > x.value); 'Aber! Das ist eine Frage für einen anderen Tag. – dvlsg

4

Gemäß den draft version of ES6,

Sobald ein Generator des "completed" Zustand eintritt, läßt es nie wieder aufgenommen wird Ausführungskontext es und der damit verbundene nie. Jeder mit dem Generator verknüpfte Ausführungszustand kann zu diesem Zeitpunkt verworfen werden.

So, es gibt keine Möglichkeit, es nach Abschluss zurückgesetzt. Es macht auch Sinn, so zu sein. Wir nennen es einen Generator, einen Grund :)

+0

Bumm. Ich vermute, dass ich C# 's Baum anbreche (was ich gewohnt bin), wo Sie foreach Schleifen auf demselben IEnumerable ausführen können, ohne es neu zu initialisieren. Ich nehme an, dass intern GetEnumerator() aufgerufen wird, was im Wesentlichen den Iterator neu erstellt. – dvlsg

11

An diesem Punkt wird iterable verbraucht.

Das bedeutet seine interne [[GeneratorState]] ist completed.

Gibt es eine Methode iterable zurück zum Startpunkt nur zum Bewegen ohne erneute Berufung Generator()

Nein, die spec Staaten

Sobald ein Generator die eintritt "completed" -Status wird nie verlassen und der zugehörige Ausführungskontext wird nie wieder aufgenommen. Jeder mit dem Generator verknüpfte Ausführungszustand kann zu diesem Zeitpunkt verworfen werden.

oder möglicherweise durch eine erneute Berufung Generator(), nur durch Prototyp mit oder Konstruktormethoden innerhalb der iterable Objekt

Nr Obwohl nicht explizit in der angegebenen Spezifikation, gibt es keine weiteren instanzspezifischen Eigenschaften auf dem iterable object als GeneratorState und GeneratorContext].

jedoch die informativen "Generator Object Relationships" grapic Zustände:

Jede Generator-Funktion hat einen zugehörigen Prototyp, der keine Konstruktor Eigenschaft hat. Daher stellt eine Generatorinstanz den Zugriff auf ihre Generatorfunktion nicht bereit.

Ich möchte in der Lage sein, die iterable

übergeben Sie die Generatorfunktion stattdessen zu einem anderen Rahmen abgehen. Oder etwas, das neue Generatorinstanzen liefert.

+0

Ich denke, das macht angesichts der aktuellen Spezifikation Sinn. Danke für die Zitate und Vorschläge. – dvlsg

2

Sie können auch Ihren Generator zurücksetzen Ihre iterable wie diese:

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

Ich weiß nicht persönlich die Vor- und Nachteile, dies zu tun. Nur dass es so funktioniert, wie Sie es erwarten würden, wenn das Iterable jedes Mal neu zugewiesen wird, wenn der Generator beendet wird.nur den Generator wie Azder Zeigte Mit mehr Wissen darüber, wie diese Arbeit würde ich empfehlen:

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

Die Version, die ich empfohlen werden Sie verhindern, dass in der Lage, durch die Iterationen zu laufen, wenn es überhaupt nicht

EDIT ... Zum Beispiel, wenn Sie auf eine URL warten, um eine andere anzurufen. Wenn die erste URL fehlschlägt, müssen Sie Ihre App aktualisieren, bevor sie diese erste Rendite erneut testen kann.

0

Immer wenn Sie ein iterables "zurücksetzen" müssen, werfen Sie einfach das alte weg und machen Sie ein neues.

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