saga-take
take, fork
by chaofeng liu
HTML
<button id="test">
Clickme
</button>
<div id="result">
</div>
JavaScript
const $btn = document.querySelector('#test');
const $result = document.querySelector('#result');
function channel() {
let taker;
function take(cb) {
taker = cb;
}
function put(input) {
if (taker) {
const tempTaker = taker;
taker = null;
tempTaker(input);
}
}
return {
put,
take,
};
}
const chan = channel();
let i = 0;
$btn.addEventListener('click', () => {
chan.put(`action data${i++}`);
}, false);
function take() {
return {
type: 'take'
};
}
function fork(cb) {
return {
type: 'fork',
fn: cb,
};
}
function* takeEvery(worker) {
yield fork(function* () {
while(true) {
const action = yield take();
worker(action);
}
});
}
function* mainSaga() {
yield takeEvery(action => {
$result.innerHTML = action;
});
}
function runTakeEffect(effect, cb) {
chan.take(input => {
cb(input);
});
}
function runForkEffect(effect, cb) {
task(effect.fn || effect);
cb();
}
function task(iterator) {
const iter = typeof iterator === 'function' ? iterator() : iterator;
function next(args) {
const result = iter.next(args);
if (!result.done) {
const data = result.value;
if (typeof data[Symbol.iterator] === 'function') {
runForkEffect(data, next);
} else if (data.type) {
switch (data.type) {
case 'take':
runTakeEffect(result.value, next);
break;
case 'fork':
runForkEffect(result.value, next);
break;
default:
}
}
}
}
next();
}
task(mainSaga);