响应式编程:如何订阅和采样事件发射器?

时间:2019-02-05 09:44:06

标签: javascript react-native rxjs eventemitter

我正在使用消耗react-native-ble-manager的React Native应用程序中的事件发射器。

handleUpdateValueForCharacteristic(data) {

    console.log('Received data from ' + data.peripheral + ' characteristic ' + data.characteristic, data.value);

  }
bleManagerEmitter.addListener('BleManagerDidUpdateValueForCharacteristic', this.handleUpdateValueForCharacteristic );

我正在处理的蓝牙事件流的频率为每秒50、100或200个事件(Hz)。

我在所有事件中都以50 Hz的频率被打扰,其中一半发生在100 Hz的情况,四分之一发生在200 Hz。 用RxJS订阅此事件流的正确方法是什么?应该使用哪个运算符采样数据?

我可能是错的,但是我似乎找不到用于从事件发射器创建可观察对象的辅助方法。

1 个答案:

答案 0 :(得分:0)

fromEventPattern应该是您想要的。

它使您可以基于自定义事件发射(如您使用此BLE管理器所获得的)创建可观察对象。

我在下面提供了一个摘要,概述了如何使用它。

注意scan()filter()的组合。通过使用前一个运算符来跟踪第n个 事件,它可以有效地更改事件的采样率,从而可以由任何订户处理。

在您的情况下,您希望scan()还要跟踪事件的发出,因此您可以在map()通话之后最终filter()进行订阅,以便订阅者可以接收到它。关键是要在累积事件时跟踪scan()内的事件状态(即滴答和事件数据属性,分别为代码段中的tdata)。

const { fromEventPattern } = rxjs;
const { filter, map, scan } = rxjs.operators;

// Tweak parameters to vary demo
const hz = 200;
const sample = 4;

function addEmitterHandler(handler) {
  // bleManagerEmitter.addListener('event', handler)
  const intervalId = setInterval(() => {
    handler({ timestamp: Date.now() });
  }, 1000 / hz);
  return intervalId;
}

function removeEmitterHandler(handler, intervalId) {
  // bleManagerEmitter.removeListener(...)
  clearInterval(intervalId);
}

// Simulate emissions using the `setInterval()` call
const emitter = fromEventPattern(
  addEmitterHandler,
  removeEmitterHandler
);

emitter.pipe(
  // Use `scan()` and `filter()` combination to adjust sampling
  scan((state, data) => {
    const t = (state.t % (sample + 1)) + 1;
    return { t, data };
  }, { t: 0, data: null }),
  filter(state => state.t % sample === 0),
  // Use `map()` to forward event data only
  map(state => state.data),
).subscribe(data => console.log(data));
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.4.0/rxjs.umd.min.js"></script>