使用种族优先渠道,redux-saga

时间:2016-11-28 07:15:43

标签: redux-saga

让我们说有两个动作通道,其中一个动作必须始终在另一个之前处理。

假设

是否安全
const priChannel = yield actionChannel('INTERNAL_PROCESS_COMMAND')
const secChannel = yield actionChannel('PROCESS_COMMAND')

const {pri, sec} = race({pri: take(priChannel), sec: take(secChannel)})

...总是会从priChannel中选择,如果它有待处理的操作 - 而不是同时从secChannel弹出?在主循环中一直取消其中一个需要是否效率低下?有更好的方法,比如priChannel.Buffer.isEmpty()

1 个答案:

答案 0 :(得分:1)

基于自定义(优先级)缓冲区的解决方案:

import { buffers, delay } from 'redux-saga';
import { actionChannel, take, call } from 'redux-saga/effects';

import {
  DECREMENT, decrementActionCreator, INCREMENT, incrementActionCreator, reducer
} from '../reducers/counter';
import { logger } from '../utils';

const name = '13/Channel Custom Buffer';
const log = logger(name);

const delayTime = 10;

const prioBuffer = function(initialSize, highPrioActions, loPrioActions) {
  highPrioActions = Array.isArray(highPrioActions) ? highPrioActions : [highPrioActions];
  loPrioActions = Array.isArray(loPrioActions) ? loPrioActions : [loPrioActions];

  const highPrioBuffer = buffers.expanding(initialSize);
  const loPrioBuffer = buffers.expanding(initialSize);


  const put = (it) => {
    if (highPrioActions.indexOf(it.type) !== -1) {
      highPrioBuffer.put(it);
    }
    if (loPrioActions.indexOf(it.type) !== -1) {
      loPrioBuffer.put(it);
    }
  };
  const take = () => {
    if (!highPrioBuffer.isEmpty()) {
      return highPrioBuffer.take();
    }
    if (!loPrioBuffer.isEmpty()) {
      return loPrioBuffer.take();
    }
  };
  const flush = () => {
    const items = highPrioBuffer.flush();
    items.concat(loPrioBuffer.flush());
    return items;
  };
  const isEmpty = () => {
    return highPrioBuffer.isEmpty() && loPrioBuffer.isEmpty();
  };

  return {
    put, take, flush, isEmpty
  };
};

function* takeChannelSaga() {
  const channel = yield actionChannel([INCREMENT, DECREMENT], prioBuffer(8, INCREMENT, DECREMENT));
  while (true) { // eslint-disable-line no-constant-condition
    const takeAction = yield take(channel);
    log('takeChannelSaga :: takeAction', takeAction);
    yield call(delay, delayTime);
    log(`takeChannelSaga :: delay ${delayTime}`);
  }

}

export default  {
  name,
  saga: takeChannelSaga,
  reducer: reducer,
  useThunk: !true,
  n: 3,
  execute(store) {
    return new Promise(resolve => {
      let i = 0;
      const dispatch = () => {
        if (i++ < this.n) {
          log(`dispatch decrementActionCreator(${i})`);
          store.dispatch(decrementActionCreator(i));
          log(`dispatch incrementActionCreator(${i})`);
          store.dispatch(incrementActionCreator(i));
          return setTimeout(dispatch, delayTime);
        }
        // done
        setTimeout(() => resolve(this), 2 * this.n * delayTime);
      };
      dispatch();
    });
  }
};

相应的日志:

  00000005: [Runner] ---------- running example 13/Channel Custom Buffer
  00000006: [Runner] store initial state 0
  00000011: [13/Channel Custom Buffer] dispatch decrementActionCreator(1)
  00000013: [13/Channel Custom Buffer] takeChannelSaga :: takeAction Object {type: "REDUCER/COUNTER/DECREMENT", payload: 1}
  00000014: [13/Channel Custom Buffer] dispatch incrementActionCreator(1)
* 00000048: [13/Channel Custom Buffer] takeChannelSaga :: delay 10
  00000048: [13/Channel Custom Buffer] takeChannelSaga :: takeAction Object {type: "REDUCER/COUNTER/INCREMENT", payload: 1}
  00000051: [13/Channel Custom Buffer] dispatch decrementActionCreator(2)
  00000051: [13/Channel Custom Buffer] dispatch incrementActionCreator(2)
  00000060: [13/Channel Custom Buffer] takeChannelSaga :: delay 10
  00000061: [13/Channel Custom Buffer] takeChannelSaga :: takeAction Object {type: "REDUCER/COUNTER/INCREMENT", payload: 2}
  00000062: [13/Channel Custom Buffer] dispatch decrementActionCreator(3)
  00000063: [13/Channel Custom Buffer] dispatch incrementActionCreator(3)
  00000073: [13/Channel Custom Buffer] takeChannelSaga :: delay 10
  00000074: [13/Channel Custom Buffer] takeChannelSaga :: takeAction Object {type: "REDUCER/COUNTER/INCREMENT", payload: 3}
* 00000086: [13/Channel Custom Buffer] takeChannelSaga :: delay 10
  00000086: [13/Channel Custom Buffer] takeChannelSaga :: takeAction Object {type: "REDUCER/COUNTER/DECREMENT", payload: 2}
* 00000098: [13/Channel Custom Buffer] takeChannelSaga :: delay 10
  00000099: [13/Channel Custom Buffer] takeChannelSaga :: takeAction Object {type: "REDUCER/COUNTER/DECREMENT", payload: 3}
* 00000112: [13/Channel Custom Buffer] takeChannelSaga :: delay 10
* 00000120: [Runner] store final state 0
  00000120: [Runner] ---------- example 13/Channel Custom Buffer is done

希望这会对你有所帮助。