简体   繁体   English

如何根据rxjs中的缓冲区内容缓冲一个observable?

[英]How to buffer an observable based on buffer content in rxjs?

I would like to flush a buffered observable based on the content of the buffer, but how to accomplish this? 我想根据缓冲区的内容刷新缓冲的observable,但是如何实现呢? A simplified example of what I want to do: 我想要做的简化示例:

observable.buffer(() => {
  // Filter based on the buffer content.
  // Assuming an observable here because buffer()
  // needs to return an observable.
  return buffer.filter(...);
})

Here is more specifically what I am trying to do with key events (bin here ): 这里更具体地说明了我要对关键事件做什么(bin 这里 ):

const handledKeySequences = ['1|2']

// Mock for document keydown event
keyCodes = Rx.Observable.from([1,2,3,4])

keyCodes
  .buffer(() => {
    /*
      The following doesn't work because it needs to be an
      observable, but how to observe what is in the buffer?
      Also would like to not duplicate the join and includes
      if possible
      return function (buffer) {
        return handledKeySequences.includes(buffer.join('|'));
      };
    */

    // Returning an empty subject to flush the buffer
    // every time to prevent an error, but this is not
    // what I want.
    return new Rx.Subject();
  })
  .map((buffer) => {
    return buffer.join('|')
  })
  .filter((sequenceId) => {
    return handledKeySequences.includes(sequenceId);
  })
  .subscribe((sequenceId) => {
    // Expecting to be called once with 1|2
    console.log("HANDLING", sequenceId)
  })

I feel like my approach is wrong, but I can't figure out what the right approach would be. 我觉得我的方法是错的,但我无法弄清楚正确的方法是什么。 I've tried using scan , but that scans all the events in the observable, which is not what I want. 我尝试过使用scan ,但会扫描observable中的所有事件,这不是我想要的。

Thanks for any help! 谢谢你的帮助!

This should be doable with bufferWithCount : 这应该可以使用bufferWithCount

const handledKeySequences = ['1|2']

// Mock for document keydown event
keyCodes = Rx.Observable.from([0,1,2,3,4]);

const buffer$ = keyCodes
  .bufferWithCount(2, 1)  // first param = longest possible sequence, second param = param1 - 1
  .do(console.log)
  .map((buffer) => {
    return buffer.join('|')
  })
  .filter((sequenceId) => {
    return handledKeySequences.includes(sequenceId);

  });

  buffer$.subscribe((sequenceId) => {
    console.log("HANDLING", sequenceId)
  });

See live here . 看到这里住。

Also have a look at this question. 还看看这个问题。

It seems that this functionality is not currently available in Rxjs, so as suggested by @olsn I wrote a custom operator that works by passing a function to tell when to flush the buffer: 似乎这个功能目前在Rxjs中不可用,所以正如@olsn所建议的那样,我编写了一个自定义运算符,它通过传递函数来告知何时刷新缓冲区:

(function() {

  // Buffer with function support.
  function bufferWithContent(bufferFn) {
    let buffer = [];

    return this.flatMap(item => {
      buffer.push(item);
      if (bufferFn(buffer)) {
        // Flush buffer and return mapped.
        let result = Rx.Observable.just(buffer);
        buffer = [];
      } else {
        // Return empty and retain buffer.
        let result = Rx.Observable.empty();
      }
      return result;
    });
  }

  Rx.Observable.prototype.bufferWithContent = bufferWithContent;

})();

I also opened an issue here that proposes adding this functionality. 我还在这里提出了一个建议添加此功能的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM