2

我和一位同事向我们的 android 应用程序添加了一个类似 redux-observable 的流程,但无法弄清楚如何创建一个在第一次调用完成之前停止接收操作的史诗。

最初我以为我们可以使用skipUntil(),但后来意识到结果skipUntil()被吞下,并且从未传递给链条的其余部分。

下面是一些粗略的 JS 代码,展示了我们希望完成的工作。

  const fetchUserEpic = action$ =>
  action$.ofType(FETCH_USER)
    .skipUntil( /* first request completes */ )
    .mergeMap(action =>
      ajax.getJSON(`/api/users/${action.payload}`)
        .map(response => fetchUserFulfilled(response))
        .takeUntil(action$.ofType(FETCH_USER_CANCELLED))
    );

这几乎就像我需要一个skipMap()操作员,它的行为就像switchMap()但一次只尊重一个请求,而如果一个可观察的正在进行,则忽略所有项目。

感谢您的任何建议。

4

2 回答 2

4

假设您非常确定这是您需要的(通常不是,在执行先前的查询时删除输入意味着结果已过时,switchMap和/或debounce通常是首选),take(1) + repeat应该可以工作,因为可观察的操作很热。

const fetchUserEpic = action$ =>
  action$.ofType(FETCH_USER)
    .take(1)
    .concatMap(action =>
      ajax.getJSON(`/api/users/${action.payload}`)
        .map(response => fetchUserFulfilled(response))
        .takeUntil(action$.ofType(FETCH_USER_CANCELLED))
    )
    .repeat()

这是一个模拟逻辑的片段。

// simulate action$.ofType(FETCH_USER) every second
const obs1 = Rx.Observable.interval(1000).publish()
obs1.connect()

function getStuff(i) {
  return Rx.Observable.timer(i*1000).mapTo(i)
}

obs1.take(1).concatMap(getStuff).repeat().subscribe(console.log)
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.0.2/Rx.js"></script>

于 2017-01-05T16:50:05.393 回答
3

你不需要做任何花哨的事情,已经有一个称为exhaustMap. exhaustMap类似于,concatMap只是它会静默丢弃在前一个仍在处理时传入的请求。

const fetchUserEpic = action$ =>
  action$.ofType(FETCH_USER)
    .exhaustMap(action =>
      ajax.getJSON(`/api/users/${action.payload}`)
        .map(response => fetchUserFulfilled(response))
        .takeUntil(action$.ofType(FETCH_USER_CANCELLED))
    );
于 2017-01-05T21:04:20.990 回答