问题:我想创建Rxjs组合(函数链),这将导致从一个Observable缓冲值,直到某个事件发生,然后同步发送所有缓冲的值,然后缓冲直到下一个事件。
我使用此函数来收集所有必须等到我的应用程序拨打授权电话的http请求。然后运行所有这些请求。 (它在Angular4 HttpClient拦截器中实现),这就是我的用例,但我通常会寻求如何创建这样的rx链的解决方案。
为什么Rxjs缓冲区并不令人满意。从我读取和测试的缓冲区要么需要精确的时间帧,或者在获得调度程序而不是时间作为参数的情况下,它在检测到最后一个调度程序"事件"之后重新订阅调度程序。传播。我希望它的工作方式如下:当出现第一个请求时,我开始缓冲然后订阅调度程序,在调度程序发出后,停止缓冲,重新发送所有缓冲的值,并等待下一个新请求再次开始缓冲并且再次启动调度程序。
现在我的解决方案是使用未定义或我的可观察的辅助对象,代码大致如下:
private observable: Observable<boolean>;
makeRequest(): Observable<boolean> {
if (this.observable !== void 0) {
return this.observable;
} else {
this.observable = this.authenticationReuqest()
.share()
.finally(() => this.observable = void 0);
return this.observable;
}
}
通过这种方式,我可以缓冲我的请求,通过捕捉它们.delay()直到相同的多重观察发射,并且在它发出之后我只是清理它(尽管不需要取消订阅因为它最终清理完所以在完成之后或错误)。
如果有人有想法或模式如何用纯Rxjs替换这个解决方案,我很感兴趣。我有一些感觉,虽然我无法得到确切的解决方案,但Buffer和Zip的某些组合可以实现它。
由于 托马斯
答案 0 :(得分:0)
你应该使用bufferWhen:它会从一个observable缓冲值,直到第二个值发出。
答案 1 :(得分:0)
我遇到了完全相同的问题,我有像这样的事件
我提前开始加载活动,以便我们不需要等待。但问题是,只有在一点之后(&#34; rdy&#34;,代表准备就绪)我想处理这些事件。因此,准备好的事件需要先行。我需要保持这些值直到准备就绪并重新发送它们。喜欢这个
以下是我的工作,我使用multicast
在下游分享相同的订阅。在选择器函数中创建一个ready observable,过滤第一个ready事件。然后合并ready的observable和多播事件的缓冲区,取一个,并将switchMap从数组返回到值。最后结束多重事件。这是代码
const events = [
'ev1',
'ev2',
'ready',
'ev3',
'ev4',
'ev5'
]
Rx.Observable
.interval(500)
.take(events.length)
.map(i => events[i])
.multicast(
() => new Rx.Subject(),
events$ => {
const ready$ = events$
.filter(event => event === 'ready')
.take(1)
return Rx.Observable
.merge(
ready$,
events$
.buffer(ready$)
.take(1)
.switchMap(events => Rx.Observable.from(events))
)
.concat(events$)
}
)
或者你可以找到它并在RxViz上运行https://rxviz.com/v/j8nNpe8N 它不漂亮,但它有效。我还在寻找一种更好的方法,任何想法?
答案 2 :(得分:0)
我也花了一些时间研究这个确切的问题,但我无法弄清楚。最后,我得到了以下工作。我相信必须有一种更加惯用/优雅的方法,但是作为RxJS的新用户,我能够理解这种方法。
import { fromEvent } from "rxjs";
import { tap, scan, filter, map } from "rxjs/operators";
const clicks = fromEvent(document, "click").pipe(
scan(acc => acc + 1, 0),
tap((v) => console.log("tapping", v))
);
const out = clicks.pipe(
// tap(v => console.log('before scan', v)),
scan((acc, count) => {
if (count % 3 === 0) {
return {acc: [], out: acc.acc.concat(count)}
}
return {out: [], acc: acc.acc.concat(count)}
}, {acc: [] as number[], out: [] as number[]}),
// tap(v => console.log('after scan', v)),
filter(obj => obj.out.length > 0),
map(obj => obj.out)
)
out.subscribe(v => console.log('out', v))
关键是我使用scan()
作为运行中的减速器,然后滤除了值。我从.scan()
中的每个后续值构建我自己的值“缓冲区”,然后在下一个过滤器中删除所有不具有“就绪”状态的事件。
看起来很丑,但是允许我的用例比准备好的事件复杂一些。我正在解析git-remote-helper
命令,有些命令以双换行符结尾,有些则没有。