如何为RxJS Observable中的每个发射创建一个新对象?

3

我有一个服务,可以计算给定数独的解(实现方式不重要),并在 RxJS 可观察对象中发布每个计算迭代。

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;
}
我这么做是为了以后使用 Observable.zip() 将此 observable 与 Observable.interval() 观察者组合,以带有可被人类感知的延迟显示此解决过程所经历的迭代,在我的 Angular2 组件中。 然而,当我在 Angular2 组件中设置由 Observable 发出的数据时,代码如下:
Observable.zip(this.sudokuSolverService.solve(),Observable.interval(500),(obs, timer) => {return obs}).subscribe((nextBoardFields: Field[][]) => {
        this.sudokuGame.boardFields = nextBoardFields;
    });
然后,Observable 的排放被延迟,但变化仍然立即显示。我怀疑这是因为我通过引用复制了 nextBoardFields 数组,但我不知道如何从我的 Angular2 控制器中与我的数独求解服务中的 boardFields 数组取消链接。有没有可能做到这一点?编辑:我想到的唯一方法是以某种方式使 Field 类成为不可变的(也许借助 Immutable.js),但这似乎对此问题有点复杂。
3个回答

2
我猜测你的可观察对象的问题在于它同步地一次性发出其值。因此,在同一个时刻,你有所有的被调用,并且也有。所以当你进行操作时,它会获取第一个值,等待计时器,但与此同时,你的可观察对象已经在同一时刻发出了所有的值。你可能需要做的是将迭代变量与计时器链接起来,例如:

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的回答让我朝着正确的方向前进。

关键在于,即使我使用[].concat(nextBoardFields)或Maarek的Object.assign(this.sudokuGame.boardFields, nextBoardFields)等方法复制了Field[][]数组,各个Field仍然会引用相同的对象。

为了深度复制这个数组,我利用了o.next(JSON.parse(JSON.stringify(this.sudokuGame.boardFields))),这样我就可以按照预期使用我的Observable了。


0
我使用Object.assign()来获取一个对象的值拷贝,并且断开与observable/observer的连接。这在你的情况下能行吗?
Observable.zip(this.sudokuSolverService.solve(),Observable.interval(500),(obs, timer) => {return obs}).subscribe((nextBoardFields: Field[][]) => {
    Object.assign(this.sudokuGame.boardFields, nextBoardFields);
});

我知道不可变对象也可以起作用,但我同意它会增加一层复杂性,这并不好玩。 - Maarek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,