制作复杂的可观察管道变得很困难,如果有人可以帮助我,我将不胜感激。
我有一个数据流,可以通过蓝牙给我一些值,这些值是我必须解码的数据帧。
这是一个名为RX$
的BehaviorSubject。
现在RX$
上,有时我会收到即时数据(INST),有时会收到历史数据(HIST)。使用INST,除了其他功能外,我还收到发送数据版本和模型的设备。我成功生成了一个可观察对象,该对象可以使用设备版本和模型为我计算一个JSON对象,并且只要两者都不存在就不会发出,我们称之为deviceVersionModelStream$
现在,另一方面,我以流的形式批量接收HIST数据帧,我们将其称为historyStream$
,并且由于有大量数据,我使用bufferTime(2000)
来构成数据数组并依靠我的嵌入式数据库批量插入(而不是一个接一个)。
到目前为止效果很好...
现在,我的客户添加了一条新规则,他们的设备类型很旧,无法为我提供特定案例的一些数据,但是使用相同的模式,我知道它还会给我带来什么。
因此,在解码帧并将其插入数据库之前,我需要具有设备版本和型号。
我的问题是,只要historyStream$
发出一次(我在其他地方也使用过HOT),我该如何延迟deviceVersionModelStream$
的发生?发生时,我想生成某种带有原始框架和版本/模型的JSON对象。
但是ALSO还是逐渐分发此信息,以免不像我的bufferTime(2000)那样淹没我的数据库批量插入内容。
我正在尝试使用缓冲区,mergeMap,延迟,但是我很难实现这一目标……
也许有RX实力的人可以帮助我吗?
非常感谢
答案 0 :(得分:1)
这篇文章有点旧,但我最近在寻找“缓冲 rxjs observables 直到另一个事件发生”时偶然发现了它,我想我会分享更新版本的样子。
我是在 https://thinkrx.io 上构建的。这是我使用的代码:
const { rxObserver } = require('api/v0.3');
const { timer, of, combineLatest, concat } = require('rxjs');
const { delay, take, share, buffer, mergeAll, bufferTime, filter, takeUntil, skipUntil } = require('rxjs/operators');
const historyStream$ = timer(0, 10).pipe(
share(), take(10)
);
const versionModel$ = of("A").pipe(
delay(50),
take(1)
);
historyStream$.subscribe(rxObserver('History Stream'));
versionModel$.subscribe(rxObserver('Version Model'));
combineLatest([
versionModel$,
concat([
historyStream$.pipe(buffer(versionModel$)),
historyStream$.pipe(skipUntil(versionModel$))
]).pipe(
mergeAll()
)]
).subscribe(rxObserver("Buffer Window"));
输出如下:
这里发生的事情是我们将两个 observables 传递给 concat
:一个代表缓冲的事件集,另一个代表事件进入时的流。我们最终将所有这些传递到mergeAll
以获得适当的效果。
答案 1 :(得分:0)
好像您需要在开始时暂停(缓冲)historyStream$
,然后在deviceVersionModelStream$
发出时取消暂停。暂停/取消暂停流的一种方法是。
merge(
source$.pipe(bufferToggle(pauseOn$, () => pauseOff$)),
source$.pipe(windowToggle(pauseOff$, () => pauseOn$))
).pipe(mergeAll())
另请参阅:https://medium.com/@kddsky/pauseable-observables-in-rxjs-58ce2b8c7dfd
您的情况是:
const versionModel$ = deviceVersionModelStream$.pipe(take(1));
merge(
historyStream$.pipe(bufferToggle(of(0), v => versionModel$)),
historyStream$.pipe(windowToggle(versionModel$, v => NEVER))
).pipe(
mergeAll(),
bufferTime(2000)
);
如果希望每次发射都可以访问deviceVersionModelStream$
的输出,则可以使用combineLatest
。如果遇到对historyStream$
和deviceVersionModelStream$
的多个订阅,则可以事先使用share
。
const versionModel$ = deviceVersionModelStream$.pipe(share(), take(1));
const historyStreamShared$ = historyStream$.pipe(share());
combineLatest(
versionModel$,
merge(
historyStreamShared$.pipe(bufferToggle(of(0), v => versionModel$)),
historyStreamShared$.pipe(windowToggle(versionModel$, v => NEVER))
).pipe(
mergeAll(),
bufferTime(2000)
)
).subscribe(console.log);
https://stackblitz.com/edit/rxjs-oyctsg
编辑(如果您一开始只需要一次缓冲区)
在您的情况下,您无需在关闭缓冲区后就可以再次使用它,即,一旦从bufferToggle切换到windowToggle流,则无需切换回bufferToggle流。
这允许使用仅使用buffer
而不是bufferToggle
和windowToggle
的稍微简单的方法。
source$ = dataStream.pipe(share()) // make sure this is a hot observable
pauseOff$ = timer(5000) // make sure this observable emits once and completes
concat(
source$.pipe(buffer(pauseOff$), mergeAll()), // start with a buffered stream
source$ // switch to the unbuffered stream when pauseOff$ emits and completes the previous stream
)
const historyStream$ = timer(0, 100).pipe(share(), take(200));
const versionModel$ = of("version-model").pipe(delay(5000), take(1));
combineLatest(
versionModel$,
concat(
historyStream$.pipe(buffer(versionModel$), mergeAll()),
historyStream$
).pipe(
bufferTime(2000)
)
).subscribe(console.log);