rxjs:如何通过Observables订购响应

时间:2017-11-17 13:26:58

标签: socket.io rxjs

enter image description here

我正在使用socket.io向我的前端发送一系列响应。响应旨在是顺序的,但根据socket.io创建的连接,它们并不总是保证以正确的顺序(https://github.com/josephg/ShareJS/issues/375)。

假设每个响应都有一个包含数字的序列字段(如上图中的数字所示),observable应按顺序发出这些响应。

如果无序接收到响应并且在没有得到任何响应的情况下经过了一定的时间(n),我希望我的observable发出错误,向我的前端发出信号以重置连接。 / p>

1 个答案:

答案 0 :(得分:1)

一个非常好的问题。下面是一个评论最重要部分的片段。



// mock ordered values
const mockMessages = Rx.Observable.fromEvent(document.querySelector('#emit'), 'click')
  .map((e, index) => ({
    index,
    timestamp: e.timeStamp
  }))
  .delayWhen(() => Rx.Observable.timer(Math.random() * 2000)) // distort order

// there is a lot of mutability in `keepOrder`, but all of it
// is sealed and does not leak to outside environment
const keepOrder = timeoutMs => stream =>
  Rx.Observable.defer(() => // need defer to support retries on error
    stream.scan((acc, v) => {
      acc.buffer.push(v)
      acc.buffer.sort((v1, v2) => v1.index - v2.index)
      return acc
    }, {
      lastEmitted: -1,
      buffer: []
    })
    .mergeMap(info => {
      const emission = []
      while (info.buffer.length && info.lastEmitted + 1 === info.buffer[0].index) {
        emission.push(info.buffer.shift())
        info.lastEmitted += 1
      }
      return Rx.Observable.of(emission)
    })
    .switchMap(emissions => {
      if (!emissions.length) { // this condition indicates out of order
        return Rx.Observable.timer(timeoutMs)
          .mergeMapTo(Rx.Observable
            .throw(new Error('ORDER_TIMEOUT')))
      } else {
        return Rx.Observable.from(emissions)
      }
    })
  )


mockMessages
  .do(x => console.log('mocked', x.index))
  .let(keepOrder(1000)) // decrease timeoutMs to increase error probablity
  .do(x => console.log('ORDERED', x.index))
  .retryWhen(es => es
    .do(e => console.warn('ERROR', e)))
  .subscribe()

<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.2/Rx.js"></script>

<button id="emit">EMIT</button>
&#13;
&#13;
&#13;