如果单击按钮,则跳到下一个值,否则保持计时器活动状态



我有以下代码:

startReplay(replayValues: Object) {
this.replayRunning = true;
var firstTs: number;
const repObs = Observable.from(Object.keys(replayValues)).filter(key => Object.keys(diff(replayValues[key], this.initialFormObject)).length > 0);
repObs.first().subscribe(key => firstTs = Number(key));
return repObs
.delayWhen(key => Observable.timer(Number(key) - firstTs))
.map(key => replayValues[key])
.finally(() => this.replayRunning = false)
.takeWhile(() => this.replayRunning === true);
}

我有从array发出值的observable.array将时间戳作为keysobjects作为值。我以observable运行此数组并在其他地方订阅(让我们假设打印到控制台(。

如您所见,observable在 x (=Number(key) - firstTs( 秒后发出一个值。之后,我映射它,只发出对象,不再关心时间戳。我想运行它,直到replayRunning的值true.

现在,我的app.component.html中有一个按钮,用于调用代码中skipReplayStep() {}的当前空函数。现在,我希望有可能停止delayWhen()并立即前进到下一步,即map(key =>...)已启动。

初步想法(但不是实际解决方案(

我想到了merge+first(),其中Observable.timer(Number(key) - firstTs)部分与EventEmitter合并。但我无法将EventEmitter变成Observable.另外,我认为这不是最好的方法。我的问题也是,我认为当我只想取消最近的delayWhen()时,EventEmitter会取消每delayWhen()

编辑:大理石图审判

1 |----X|
2 |------X|
3 |--------------X|
4 |--------------------X|
5 |--------------------------------X|
6 |-------------------------------------------------X|
7 |-X-----X-------------X---X--->
R |-X----XX------------XX---X|

因此,16的观察者是基于我上面描述的时间戳的计时器。7是单击事件发射器(即单击按钮时(。 结果R。如您所愿,点击被映射到相应的可观察对象。因此,第一个观察者链接到第一次点击,依此类推。这导致观察点 5 和 6 在结果Observable完成之前不会发出,因为发出了两次点击。

编辑2:大理石中的轻微错误

我认为大理石有一点错误。它没有考虑到应该保持"正常"之间的时间,从而减少Observable的整体存在。

编辑3:添加了普伦克

https://plnkr.co/edit/rV0aDTcSVf4xlnVUJNJN

这是可以玩的 Plunker。让我知道这是否有意义。我从上面的函数中对其进行了一些修剪(过滤器不适用于 Plunker,因为它依赖于其他东西,但认为它可以工作(。

如果有人想知道如何解决这个问题,也许这给了他一个想法。这解决了我的问题:

startReplay(replayValues: Object) {
this.replayRunning = true;
const obsRepValues = Observable
.from(Object.keys(replayValues))
.filter(key => Object.keys(diff(replayValues[key], this.initialFormObject)).length > 0)
const obsTimestamps = obsRepValues.map((x, i) => Number(x));
const obsValues = obsRepValues.map((x, i) => replayValues[x]);
const obsIndex = obsRepValues.map((x, i) => i + 1);
const obsTimeDiff = obsRepValues
.pairwise()
.map(key => Math.ceil((Number(key[1]) - Number(key[0])) / 100) * 100)
.startWith(0);
const obsTimeElapsed = obsTimeDiff.scan((acc, curr) => acc + curr, 0);
const obsResult = Observable.zip(obsIndex, obsTimestamps, obsValues, obsTimeDiff, obsTimeElapsed);
const obsTimer = obsResult;
return obsResult
.delayWhen(x =>
Observable.race(
Observable.interval(10).skipWhile(() => x[0] != this.currentReplayStep), //BehaviourSubject + skip(x)
Observable.interval(10).skipWhile(() => (x[0] - 1) != this.currentReplayStep).delay(x[3]) //BehaviourSubject + skip(x - 1) + delay
)
)
.takeWhile(() => this.replayRunning === true)
.do(x => {
this.currentReplayStep = x[0];
const interval: number = 100;
obsTimeDiff
.skipWhile(() => x[0] != this.currentReplayStep)
.elementAt(x[0], 0)
.switchMap(duration => Observable.timer(0, interval).mapTo(-interval).scan((acc, curr) => acc + curr, duration).map(x => x / 1000))
.takeWhile(() => this.replayRunning === true && x[0] == this.currentReplayStep)
.finally(() => this.timerValue = 0)
.subscribe(y => this.timerValue = y);
})
.map(x => x[2])
.finally(() => this.stopReplay());
}
skipToNext() {
this.currentReplayStep = this.currentReplayStep + 1;
}

我目前正在研究一种使用BehaviorSubject的解决方案,该会发出而不是obsResult。从理论上讲,这并不太难。我缺少一个发出与"上一个"Observable相同位置的运算符(或者可能不知道它(。伪代码样式:

BehaviorSubject.race(2 Observables).WantedOperator(emittingNewObservable)

最新更新