【问题标题】:Reactive Programming: How to subscribe and sample an event emitter?反应式编程:如何订阅和采样事件发射器?
【发布时间】:2019-06-29 02:22:51
【问题描述】:

我正在订阅一个使用 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 赫兹的所有事件感兴趣,其中一半的 100 赫兹,四分之一的 200 赫兹。 使用 RxJS 订阅此事件流的正确方法是什么,我应该使用哪个运算符来采样数据?

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

【问题讨论】:

  • 对其中一半和四分之一感兴趣是什么意思?
  • 我认为他的意思是每第 2 次/第 4 次活动......
  • 我的意思是,在 100Hz 时,接受 1 个事件丢弃下一个,依此类推。在 200 Hz 时,获取 1 个事件,删除接下来的 3 个事件,依此类推。
  • ..结果正是我所说的

标签: javascript react-native rxjs eventemitter


【解决方案1】:

fromEventPattern 应该是您要查找的内容。

它允许您根据自定义事件发射创建一个可观察对象(就像您使用这个 BLE 管理器所拥有的一样)。

我在下面提供了一个 sn-p,概述了您可以如何使用它。

注意scan()filter() 的组合。通过使用前一个运算符来跟踪第 nth 事件,它有效地改变了事件被采样并因此被任何订阅者处理的速率。

在您的场景中,您希望scan() 也跟踪发出的事件,因此您最终可以在filter() 调用之后map() 它,这样订阅者就会收到它。这里的关键点是在累积事件时跟踪scan() 中的事件状态(即tick 和事件数据属性,分别在sn-p 中的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>

【讨论】:

  • 在您的示例中,我如何首先获取发送到 handleUpdateValueForCharacteristic 的事件数据?
  • @OlivierMATROT,虽然我已经在我的原始答案中暗示了这一点,但我已经更新了我的 sn-p 以更明确地说明你可能如何传递事件数据。为了演示,我已经将处理程序连接起来,现在使用包含时间戳的单个数据参数进行调用。请注意scan() 现在如何跟踪滴答声(以控制采样)和要转发的事件数据。
  • 谢谢,我会在测试新代码后立即接受您的回答
  • 我会说 sn-p 已失效,因为我无法运行它。
  • @OlivierMATROT,在这种情况下,您必须使用不支持 ES2015 功能的旧浏览器(即对于 const,解构)。它应该只使用“运行代码 sn-p”按钮运行。无论如何,这是无关紧要的。我的 sn-p 不应该是你想要做的事情的逐字解决方案。我通过展示解决了这个问题:1)如何订阅自定义事件发射器,2)如何从流中采样每个固定数量的事件。
猜你喜欢
  • 2016-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-12
  • 1970-01-01
  • 1970-01-01
  • 2021-04-12
  • 2021-04-17
相关资源
最近更新 更多