RxJS:如何将多个嵌套的observable与缓冲区组合在一起

时间:2017-12-18 14:33:18

标签: javascript rxjs observable rename rxjs5

警告:RxJS newb here。

这是我的挑战:

  1. onUnlink$观察者发出......
  2. 立即开始从onAdd$观察值中捕获值,最多1秒钟(我将此分区称为onAddBuffer$)。
  3. 查询数据库(创建doc$ observable)以获取我们将用于匹配其中一个onAdd$值的模型
  4. 如果onAddBuffer$ observable中的某个值与doc$值匹配,请不要发出
  5. 如果onAddBuffer$ observable中的值均未与doc$值匹配,或者onAddBuffer$ observable从未发出,则发出doc$
  6. 这是我最好的猜测:

    // for starters, concatMap doesn't seem right -- I want a whole new stream
    const docsToRemove$ = onUnlink$.concatMap( unlinkValue => {
    
      const doc$ = Rx.Observable.fromPromise( db.File.findOne({ unlinkValue }) )
    
      const onAddBuffer$ = onAdd$
        .buffer( doc$ ) // capture events while fetching from db -- not sure about this
        .takeUntil( Rx.Observable.timer(1000) );
    
      // if there is a match, emit nothing. otherwise wait 1 second and emit doc
      return doc$.switchMap( doc =>
        Rx.Observable.race( 
          onAddBuffer$.single( added => doc.attr === added.attr ).mapTo( Rx.Observable.empty() ),
          Rx.Observable.timer( 1000 ).mapTo( doc )
        )
      );
    });
    
    docsToRemove$.subscribe( doc => {
      // should only ever be invoked (with doc -- the doc$ value) 1 second
      // after `onUnlink$` emits, when there are no matching `onAdd$`
      // values within that 1 second window.
    })
    

    这总是会发出EmptyObservable。也许是因为当没有匹配时single似乎会发出undefined,并且我认为当没有匹配时它根本不会发出?同样的事情发生在find

    如果我将single更改为filter,则不会发出任何内容。

    仅供参考:这是一个包含文件系统事件的重命名方案 - 如果在add事件的1秒内发生unlink事件并且发出的文件哈希匹配,则不执行任何操作,因为它是{{ 1}}。否则它是真的rename,它应该发出要删除的数据库文档。

1 个答案:

答案 0 :(得分:3)

我猜你怎么能这样做:

onUnlink$.concatMap(unlinkValue => {
  const doc$ = Rx.Observable.fromPromise(db.File.findOne({ unlinkValue })).share();
  const bufferDuration$ = Rx.Observable.race(Rx.Observable.timer(1000), doc$);
  const onAddBuffer$ = onAdd$.buffer(bufferDuration$);

  return Observable.forkJoin(onAddBuffer$, doc$)
    .map(([buffer, docResponse]) => { /* whatever logic you need here */ });
});

single()运算符有点棘手,因为它在源Observable完成后仅发出匹配谓词函数的项(或者在有两个项目时发出错误或没有匹配项目。)

race()也很棘手。如果其中一个源Observable完成但未发出任何值race() 将完成并且不会发出任何内容。我前段时间报告了这一点,这是正确的行为,请参阅https://github.com/ReactiveX/rxjs/issues/2641 我猜你的代码出了问题。

另请注意,.mapTo(Rx.Observable.empty())会将每个值映射到Observable的实例中。如果您想忽略所有值,可以使用filter(() => false)ignoreElements()运算符。