繁体   English   中英

如何在 RxJS/redux-observable 与 redux-saga 中对操作进行排序?

[英]How do I sequence actions in RxJS/redux-observable vs redux-saga?

我已经开始深入学习 RxJs,原因之一是掌握redux-observable副作用的方法,虽然我发现 sagas 更方便和“声明性”。 我已经学习了merge/flat/concat/switchMap操作符,但它并没有帮助我弄清楚如何在 rxjs 中对事物进行排序。

这是我所说的“排序”的一个例子,在 Timer 应用程序的实例上,可以在一段时间后安排启动,使用redux-saga

export function* timerSaga() {
  while (true) {
    yield take('START');

    const { startDelay } = yield select(); // scheduled delay

    const [cancelled] = yield race([
      take('CANCEL_START'),
      delay(startDelay)
    ]);

    if (!cancelled) {
      yield race([
        call(function*() {
           while (true) {
             yield delay(10);
             yield put({ type: 'TICK' });
           }
        }),
        take(['STOP', 'RESET']
      ]);
    }
  }
}

我发现这个例子在逻辑上非常一致和清晰。 我不知道如何使用 redux-observable 来实现它。 请简单地给我代码的平静,这些代码可以使用rxjs操作符重现相同的逻辑。

在传奇(生成器)和史诗(可观察对象)之间,改变您对事件如何到达代码的思考方式很重要。

生成器满足迭代器和可迭代协议,这涉及从源中提取值/事件(在本例中为 Redux 操作),并在这些事件到达之前阻止执行。

Observable 是而不是拉。 我们描述和命名我们感兴趣的事件流,然后我们订阅它们。 没有阻塞调用,因为我们所有的代码都是由事件发生时触发的。

此代码复制了 saga 示例中的行为。

import { interval, timer } from 'rxjs';
import { withLatestFrom, mapTo, exhaustMap, takeUntil } from 'rxjs/operators';
import { ofType } from 'redux-observable';

const myEpic = (action$, state$) => {
  // A stream of all the "cancel start" actions
  const cancelStart$ = action$.pipe(ofType('CANCEL_START'));

  // This observable will emit delayed start events that are not cancelled.
  const delayedCancellableStarts$ = action$.pipe(
    // When a start action occurs...
    ofType('START'), 

    // Grab the latest start delay value from state...
    withLatestFrom(state$, (_, { startDelay }) => startDelay),

    exhaustMap(
      // ...and emit an event after our delay, unless our cancel stream
      // emits first, then do nothing until the next start event arrives.

      // exhaustMap means we ignore all other start events while we handle
      // this one.
      (startDelay) => timer(startDelay).pipe(takeUntil(cancelStart$))
    )
  );

  // On subscribe, emit a tick action every 10ms
  const tick$ = interval(10).pipe(mapTo({ type: 'TICK' }));

  // On subscribe, emit only STOP or RESET actions
  const stopTick$ = action$.pipe(ofType('STOP', 'RESET'));

  // When a start event arrives, start ticking until we get a message to
  // stop. Ignore all start events until we stop ticking.
  return delayedCancellableStarts$.pipe(
    exhaustMap(() => tick$.pipe(takeUntil(stopTick$)))
  );
};

重要的是,即使我们正在创建和命名这些 observable 流,它们的行为也是惰性的——在订阅之前它们都不会被“激活”,当你向redux-observable中间件提供这个史诗功能时就会发生这种情况。

我假设take()返回一个 observable,还没有测试代码。 它可能可以转换为 rx 时尚,如下所示。

这里的关键是repeat()takeUntil()

// outter condition for starting ticker
forkJoin(take('START'), select())
    .pipe(
        switchMap(([, startDelay]) =>
            // inner looping ticker
            timer(10).pipe(switchMap(_ => put({type: 'TICK'})), repeat(),
                takeUntil(race(
                    take('CANCEL_START'),
                    delay(startDelay)
                ))
            )
            /////////////////////
        )
    )

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM