我有以下代码:
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);
}
我有observable
从array
发出值。 array
的时间戳为keys
和objects
作为值。我将此数组作为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
。另外,我认为,我认为这不是最佳方式。我的问题还在于,当我只想取消最近的EventEmitter
时,我认为delayWhen()
会取消每delayWhen()
个。{/ p>
1 |----X|
2 |------X|
3 |--------------X|
4 |--------------------X|
5 |--------------------------------X|
6 |-------------------------------------------------X|
7 |-X-----X-------------X---X--->
R |-X----XX------------XX---X|
因此,观察者1
到6
是基于我上面描述的时间戳的计时器。 7
是单击事件发射器(即单击按钮时)。结果是R
。正如您所希望看到的那样,点击次数被映射到相应的可观察对象。因此第一个观察者链接到第一次点击等。这导致观察者5和6不会被发射,直到结果Observable
由于发出两次点击而结束。
我认为大理石有轻微的错误。它并没有说明" normal"之间的时间。应该保留,从而减少Observable
的总体存在。
https://plnkr.co/edit/rV0aDTcSVf4xlnVUJNJN
这是可以玩的Plunker。如果这是有道理的,请告诉我。我从上面的函数中略微修剪了一下(过滤器不适用于Plunker,因为它依赖于其他东西,但认为它有效)。
答案 0 :(得分:0)
如果有人想知道如何解决这个问题,也许这会给他一个想法。这解决了我的问题:
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)