2016-11-28 6 views
0

Допустим, что есть два канала действия, где действия одного всегда должны обрабатываться перед другим.Использование гонки для определения приоритетов каналов, 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()

+0

Я бы предположил, что можно с уверенностью предположить, что для данного гоночного вызова он не будет использоваться с обоих каналов. Это может зависеть от того, как именно выполняется гонка, но я думаю, что небезопасно предполагать, что связи всегда будут нарушены в пользу priChannel. Если priChannel ожидает действия, но secChannel также делает, вы можете получить что-то из secChannel. – WuTheFWasThat

ответ

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 

Надеется, что это поможет.