2016-08-19 2 views
2

Ich habe einen Service, der die Lösung für ein bestimmtes Sudoku berechnet (Implementierung unwichtig) und jede Iteration der Berechnung in einem RxJS Observable veröffentlicht.Wie erstellt man ein neues Objekt für jede Emission von einem RxJS Observable?

solve() : Observable<Field[][]> { 
    let observable = Observable.create((o: Observer<Field[][]>)=> { 
     let iterationCount : number = 0; 
     while (!this.sudokuGame.isFinished() && iterationCount < 500) { 
      iterationCount++; 
      this.eliminateOptions(); 

      o.next(this.sudokuGame.boardFields); 
     } 
     if(this.sudokuGame.isFinished()) 
      o.complete(); 
     else 
      o.error("The game could not be finished after 500 iterations."); 
    }); 
    return observable; 
} 

Ich tue dies, damit ich später Observable.zip() kann diese beobachtbaren mit einem Observable.interval() Observer zu kombinieren, um die Iterationen dieses Lösungsprozess durch mit einer Verzögerung bemerkbar durch die Menschen in meiner Angular2-Komponente geht anzuzeigen.

Allerdings, wenn ich festgelegt, die von den beobachtbaren emittierten Daten in meinem Angular2-Komponente wie folgt:

Observable.zip(this.sudokuSolverService.solve(),Observable.interval(500),(obs, timer) => {return obs}).subscribe((nextBoardFields: Field[][]) => { 
     this.sudokuGame.boardFields = nextBoardFields; 
    }); 

Dann werden die Emissionen des beobachtbaren verzögert, aber die Änderungen zeigen sofort dennoch auf. Ich vermute, dass dies durch Kopieren der nextBoardFields -Array durch Verweis verursacht wurde, aber ich bin mir keiner Methoden bewusst, um die boardFields -Array in meinem Angular2-Controller von der boardFields -Array in meinem Sudoku-Lösung Service zu lösen.

Gibt es eine Möglichkeit, dies zu tun?

bearbeiten: Das einzige, was mir in den Sinn kommt, ist irgendwie die Field Klasse unveränderlich zu machen (vielleicht mit Hilfe von Immutable.js), die für diese Sache ein wenig kompliziert zu sein scheint.

Antwort

0

Ich habe Object.assign() verwendet, um eine kopierte Kopie eines Objekts zu erhalten und die Verbindung zum Observablen/Beobachter zu unterbrechen. Würde das in Ihrem Fall funktionieren?

Observable.zip(this.sudokuSolverService.solve(),Observable.interval(500),(obs, timer) => {return obs}).subscribe((nextBoardFields: Field[][]) => { 
    Object.assign(this.sudokuGame.boardFields, nextBoardFields); 
}); 
+0

Ich weiß, dass unveränderlich auch funktionieren würde, aber ich stimme zu, dass es eine Schicht von Komplexität hinzufügt, die keinen Spaß machen würde. – Maarek

+0

Sie sollten wirklich ein Codebeispiel geben. – Soviut

+0

Sie haben Recht, bearbeiten eingehende. – Maarek

1

Ich denke, das Problem hier mit Ihrem solve beobachtbar ist, dass es seine Werte synchron und in einem Rutsch emittiert. Also im selben Häkchen hast du alle onNext genannt, und auch die onComplete. Also, wenn Sie zip, erhält es den ersten Wert, wartet auf den Timer, aber in der Zwischenzeit hat Ihr Observable alle seine Werte auf den gleichen Tick emittiert. Was Sie wahrscheinlich tun müssen, ist Ihre Iterationsvariable in den Timer, wie verbunden haben: in der richtigen Richtung

Observable.interval(500).scan(function(_, iterationCount){ 
    // your logic here 
    return { 
    iterationCount : iterationCount 
    isFinished : // your logic here 
    boardFields : // your logic here 
    } 
}, {}) 
.doWhile(function(x){return x.iteration < 500 && !x.isFinished}) 
.map(function(x){return x.boardFields}) 
0

Maarek Antwort schob mich.

Der Schlüssel war, dass selbst wenn ich die Field[][] -Array mit Methoden wie [].concat(nextBoardFields) oder Maarek des Object.assign(this.sudokuGame.boardFields, nextBoardFields) die einzelnen Field ‚s würde immer noch auf die gleichen Objekte kopiert.

Um dieses Array tief zu kopieren, habe ich o.next(JSON.parse(JSON.stringify(this.sudokuGame.boardFields))) verwendet, die mir erlaubt, meine Observable wie vorgesehen zu verwenden.

Verwandte Themen