与rxjs中的其他运算符组合expand

时间:2018-07-13 17:31:26

标签: rxjs

假设我有一组重写规则,希望我的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.

通过将值分组为AB听起来像groupBy的工作,并计算每个声音的输出数量,例如scan,但是如何将这些运算符与expand组合在一起?

1 个答案:

答案 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