让我们说有两个动作通道,其中一个动作必须始终在另一个之前处理。
假设
是否安全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()
答案 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
希望这会对你有所帮助。