rxjs的条件发射延迟

时间:2017-05-11 10:28:45

标签: angular rxjs observable reactive-programming rxjs5

a-thousand-words

从图片到代码?

如何从数据和门中获取Out observable?

  • 数据是任何类型的可观察数据,例如:要发送到远程后端的JSON对象
  • Gates是一个布尔可观察对象,其中刻度线对应于true,十字架对应于false。例如,互联网连接,即true表示网络可访问,而false表示断开连接。
  • Out是生成的observable,它与Data一样发出,有时会立即发出,有时会延迟,具体取决于前面的门。例如,我可以订阅Out,以便在连接到Internet时将发出的JSON对象发布到远程API。

4 个答案:

答案 0 :(得分:2)

根据我的理解,当data$发出真实时你需要gates$,而data$则需要缓冲,否则当gates$再次发出真假时结束,所以......如: / p>

out$ = gates$.switchMap(x => x? data$ : data$.buffer(gates$))

假设:data$gates$是热流(参见此处RestSharp的含义)。

这未经过测试,但请尝试一下,让我们知道它是否确实有用(或者用你说的代码证明它:-)。逻辑看起来没问题,我只是不确定重入gates$。希望来自buffer的内门$ suscription在外部之前发射。如果没有发生这种情况,您将看到与网络停机时间相对应的数据发布暂停。

好吧,如果这不起作用,那么scan的标准解决方案就会出现。您寻找的行为可以表示为(微小)状态机,具有两种状态:passthroughbuffering。您可以使用scan实现所有此类状态机。

此处scan解决方案:Hot and Cold observables : are there 'hot' and 'cold' operators?

const gates$ = Rx.Observable.interval(2000)
                            .map(_ => Math.random() >= 0.5)
                            .map(x => ({gates: x}))
                            .share()

const data$ = Rx.Observable.interval(500)
                           .map(_ => "data"+ _)
                           .map(x => ({data: x}))                           
                           .share()

const out$ = Rx.Observable.merge(gates$, data$).scan((acc, val) => {
  if (acc.controlState === 'passthrough'){
    if (Object.keys(val).includes('data')) {
      return {
        controlState : 'passthrough',
        bufferedData : [],
        out : val.data
      }
    }
    if (Object.keys(val).includes('gates')) {
      if (val.gates) {
        // gates passing from true to true -> no changes to perform
        return {
        controlState : 'passthrough',
        bufferedData : [],
        out : null
        }
      } else {
        // gates passing from true to false, switch control state
        return {
        controlState : 'buffered',
        bufferedData : [],
        out : null        
        }
      }      
    }
  }
  if (acc.controlState === 'buffered'){
    if (Object.keys(val).includes('data')) {
      return {
        controlState : 'buffered',
        bufferedData : (acc.bufferedData.push(val.data), acc.bufferedData),
        out : null              
      }
    }
    if (Object.keys(val).includes('gates')) {
      if (val.gates) {
        // gates from false to true -> switch control state and pass the buffered data
        return {
          controlState : 'passthrough',
          bufferedData : [],
          out : acc.bufferedData              
        }
      } else {
        // gates from false to false -> nothing to do
        return {
          controlState : 'buffered',
          bufferedData : acc.bufferedData,
          out : null                    
        }
      }
    }
  }
}, {controlState : 'passthrough', bufferedData : [], out:null})
.filter(x => x.out)
.flatMap(x => Array.isArray(x.out) ? Rx.Observable.from(x.out) : Rx.Observable.of(x.out))

out$.subscribe(_ => console.log(_))   

您可以在此处看到完全相同的技术:https://jsfiddle.net/1znvwyzc/

答案 1 :(得分:0)

const gate$ = Rx.Observable.interval(2000)
                           .map(_ => Math.random() >= 0.5)
                           .filter(_ => _)


const data$ = Rx.Observable.interval(500)
                            .map(_ => "data"+ _)
                            .buffer(gate$)
                            .flatMap(_ => Rx.Observable.from(_))

data$.subscribe(_ => console.log(_))                          

门流产生随机的真值和假值(例如,n / w是向上或向下)。我们只发出此流中的真实值

基于此流的truthy值,我们缓冲数据流。

见小提琴 - fiddle。别忘了打开浏览器控制台:)

答案 2 :(得分:0)

受到这篇文章的贡献的启发,以下内容似乎产生了预期的行为:

const ticks$ = gates$.filter(b => b)
const crosses$ = gates$.filter(b => !b)
const tickedData$ = data$.windowToggle(ticks$, _ => crosses$.take(1)).switch()
const crossedDataBuffers$ = data$.bufferToggle(crosses$, _ => ticks$.take(1))
const crossedData$ = Rx.Observable.from(crossedDataBuffers$)
const out$ = tickedData$.merge(crossedData$)

可能会变得更简单,在https://jsfiddle.net/KristjanLaane/6kbgnp41/

进行游戏

答案 3 :(得分:0)

有条件地延迟数据$的另一种方法是使用delayWhen()这样的

const gate$ = new BehaviorSubject<boolean>(false);
const triggerF = _ => gate$.pipe(filter(v => v));
const out$ = data$
  .pipe(delayWhen(triggerF))              
  .subscribe( (v) => console.log(v));

// then trigger gate$, for instance:
setTimeout(() => gate$.next(true), 5000);
setTimeout(() => gate$.next(false), 10000);