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

时间:2016-08-19 17:40:36

标签: javascript angular typescript rxjs

我有一个服务来计算给定数独(实现不重要)的解决方案,并在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;
}

我这样做,以便稍后我可以使用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 - 数组引起的,但是我不知道有任何方法要取消boardFields - 我的Angular2控制器中的数组与boardFields - 数组的链接在我的数独解决服务中。

有可能这样做吗?

编辑:我唯一想到的就是以某种方式使Field类不可变(也许在Immutable.js的帮助下),这似乎有点复杂物质

3 个答案:

答案 0 :(得分:1)

我猜你的solve可观察对象的问题是它同步并一次性发出它的值。因此,在同一个刻度中,您调用了所有onNext,以及onComplete。因此当你zip时,它获得第一个值,等待计时器,但同时,你的observable在同一个tick上发出了它的所有值。您可能需要做的是将迭代变量链接到计时器,例如:

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

答案 1 :(得分:0)

我使用Object.assign()获取对象的by值副本并断开与observable / observer的连接。这会对你的情况有用吗?

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

答案 2 :(得分:0)

Maarek的回答让我朝着正确的方向前进。

关键是,即使我使用Field[][]或Maarek&#39; [].concat(nextBoardFields)等方法复制Object.assign(this.sudokuGame.boardFields, nextBoardFields) - 数组,个人Field&#39 ; s仍然会引用相同的对象。

为了深度复制这个数组,我使用了o.next(JSON.parse(JSON.stringify(this.sudokuGame.boardFields))),它允许我按预期使用我的Observable。