RxJ在流上的延迟或下一个事件之后发出

时间:2018-04-30 02:52:04

标签: rxjs redux-observable

我有一对事件:add1 / add2 / etc和remove1 / remove2 /等。我喜欢以下内容:

  • 在流上发出add1
    • 如果DELAY发生,没有新的add*排放
      • 发出remove1
    • 如果发出add*
      • 立即为remove1发出add1
      • remove*
      • 之后为add*发出DELAY

对于流上的add*的所有排放,这应该继续。

这是我在本案例中使用RxJS大理石测试编写的测试:

import test from 'tape'
import { set, lensPath } from 'ramda'
import { TestScheduler } from 'rxjs/testing'
import hideAfterDelay from '../another/file'
import { actionCreators } from '../another/dir'

const prefix = 'epics -> notifications'

test(`${prefix} -> hideAfterDelay`, t => {
  t.plan(1)

  const scheduler = new TestScheduler(t.deepEqual)

  const actionMap = {
    a: createAddAction('hello!'),
    b: createAddAction('goodbye!'),
    x: actionCreators.notifications.remove('hello!'),
    y: actionCreators.notifications.remove('goodbye!')
  }

  scheduler.run(({ cold, expectObservable }) => {
    const actionStream = cold('a-------a-b-a------', actionMap)
    const expected =          '-----x-----x-y----x'
    const actual = hideAfterDelay(5)(actionStream)

    expectObservable(actual).toBe(expected, actionMap)
  })
})

function createAddAction (name) {
  const action = actionCreators.notifications.add(name)
  const lens = lensPath(['payload', 'id'])

  return set(lens, name, action)
}

认为测试代表了我上面描述的和我想要的行为。

我怎么写这个可观察的?我已尝试使用timerrace,但我还没有能够使用此功能......

这是一部使用redux-observable,btw。

的史诗

使用RxJS v6

1 个答案:

答案 0 :(得分:0)

好的,我认为我使用了一个闭包并稍微修改了我的测试断言的工作解决方案。

首先,预期的大理石图应该如下所示

//   input:    a-------a-b-a------
// - expected: -----x-----x-y----x
// + expected: -----x----x-y----x
//
// Note above that the middle x and y emit at the same time as new
// `add*` actions on the source stream instead of one frame later

通过这个小小的改变 - 仍然与我在问题中的描述一致 - 我能够通过以下方式通过测试:

import { of, timer, empty } from 'rxjs'
import { switchMap, mapTo, tap, merge } from 'rxjs/operators'
import { ofType } from '../operators'
import actionTypes from '../../actionTypes/notifications'
import { actionCreators } from '../..'

export default (delay = 3000) => actionStream => {
  let immediateRemove

  return actionStream.pipe(
    ofType(actionTypes.ADD),
    switchMap(action => {
      let obs = empty()

      if (immediateRemove) {
        obs = of(immediateRemove)
      }

      const remove = actionCreators.notifications.remove(action.payload.id)

      immediateRemove = remove

      return obs.pipe(
        merge(
          timer(delay).pipe(
            tap(() => {
              immediateRemove = null
            }),
            mapTo(remove)
          )
        )
      )
    })
  )
}

我不知道这是解决问题的最佳或正确方法,但我确信这是 方式。