如何取消反应流中的事件?

时间:2017-08-09 16:45:40

标签: stream rxjs reactive-programming

我是反应式编程的新手,并且难以使用“一切都可以成为流”的口头禅。我正在考虑以下场景 - 我有一个 websocket事件流,如下所示:

Rx.Observable.create((observer) => {

    io.on('connect', function(socket){

      socket.on("enroll", function(player) {
        observer.next({
          event: 'enroll',
          player,
          socket
        });
      });

      socket.on('resign', function(player){
        observer.next({
          event: 'resign',
          player,
          socket
        });
      });

    });

    return {
      dispose: io.close
    };
  });

然后我可以做类似

的事情
enrollmentStream = events$
      .filter(find({ event: "enroll" }))
      .map(pick('player'));

同样

resignationStream = events$
      .filter(find({ event: "resign" }))
      .map(pick('player'));

我想在一个流中收集已注册的玩家,这些玩家将在4个批处理中进行批量处理,但显然这应仅针对在注册流中但不在resignationStream中的用户或至少最后一个事件是注册的用户。我该怎么做?

这是大理石图。

Marble diagram

有5名球员报名参赛。当有4名球员注册时,比赛开始。请注意,第二个玩家(紫罗兰色)注册但随后辞职,所以游戏不是以蓝色大理石开始,而是下一个 - 黄色 - 因为只有在那之后才有4名玩家准备就绪。

可能应该有一些像“没有”的流操作 ...是吗?

1 个答案:

答案 0 :(得分:2)

我认为在这种情况下,您可以使用combineLatest()scan()运算符,然后自行列出未签名的玩家:

const bufferedEnrollment = enrollmentStream.scan((acc, val) => { acc.push(val); return acc; }, []);
const bufferedResignation = enrollmentStream.scan((acc, val) => { acc.push(val); return acc; }, []);

Observable.combineLatest(bufferedEnrollment, bufferedResignation)
  .map(values => {
    const enrolled = values[0];
    const resigned = values[1];

    // remove resigned players from `enrolled` array
    return enrolled;
  })
  .filter(players => players.length === 4)
  .subscribe(...)

scan()运算符仅用于将玩家收集到阵列中。例如,如果您希望能够重置数组,则可以将其与另一个Observable合并。

enrollmentStream
  .merge(resetStream)
  .scan((acc, val) => {
    if (!val) {
      return [];
    }
    acc.push(val);
    return acc;
  }, []);

(由于显而易见的原因,我没有测试此代码)。