假设我有一组重写规则,希望我的Observable实现:
A => B B
B => C
也就是说,每当观察到一个A
时,就输出两个B
。每当有B
时(即使它来自A
),也要输出C
。这个
似乎是expand
的自然用例,它是pretty easy to implement。正如预期的那样,每个A
都变成了ABCBC
。
但是,如果我想将扩展与另一个运算符结合在一起怎么办?假设我的规则是:
A => B repeated N times, where N is the number of "A"s so far.
B => C, but only if the number of "B"s so far is divisible by 10.
通过将值分组为A
或B
听起来像groupBy
的工作,并计算每个声音的输出数量,例如scan
,但是如何将这些运算符与expand
组合在一起?
答案 0 :(得分:0)
迟到了两年,并不是严格地回答您的问题,而是另一种方法可以产生相同的结果,并且可能更容易建立。
此方法以递归方式构建您的流。您可能会使用类似的想法来构建一个nieve解析器。
function recursiveOperator(){
return s => s.pipe(
mergeMap(val => concat(
of(val),
streamFor(val)
))
)
}
function streamFor(x){
let stream;
if (x == 'A') {
stream = from(['B','B']);
}else if (x == 'B') {
stream = of('C');
}else{
stream = EMPTY;
}
return stream.pipe(
recursiveOperator()
)
}
zip(
timer(0, 4000),
from(['A','B','A'])
).pipe(
map(([x,y]) => y),
recursiveOperator()
).subscribe(console.log);
输出:
abcbc // Then wait 4 seconds
bc // Then wait 4 seconds
abcbc
我很确定这会带来竞争状况。因为JS是单线程的并且事件循环是可预测的,所以它们得到了一致的解决,但是您有两个流,每个流将值推送到同一主题,并且我还没有内置任何可以确保不会发生不必要的交错的东西。
但是,通过一些调整,对于大型输入而言,这可能会表现得更好。
const valueSubject = new Subject<string>();
valueSubject.subscribe(console.log);
zip(
timer(0, 4000),
from(['A', 'B', 'A'])
).pipe(
map(([x,y]) => y)
).subscribe(val => valueSubject.next(val));
valueSubject.pipe(
tap(val => {
if (val == 'A') {
valueSubject.next('B');
valueSubject.next('B');
}else if (val == 'B') {
valueSubject.next('C');
}
})
).subscribe();
输出:
abcbc // Then wait 4 seconds
bc // Then wait 4 seconds
abcbc