const symbol = Symbol('IS_GEN') const makeGen = (gen) => gen[symbol] = true const isGen = (gen) => Boolean(gen[symbol]) function takeLatest(action, fnGenerator) { makeGen(fnGenerator) return { effect: "takeLatest", action, fnGenerator } } function take(action, ) { return { effect: "take", action, } } function put(action) { return { effect: "put", action, } } function fork(fnGenerator) { makeGen(fnGenerator) return { effect: "fork", fnGenerator } } function cancel(action, fnGenerator) { return { effect: "cancel", action, fnGenerator } } function* actionA(payload) { console.log("=> actionA") yield put("ACTION-B") } function* actionB(payload) { console.log("=> actionB") const taskId = yield fork(actionC) console.log("=> actionB - fim") yield take("ACTION-CANCEL") console.log("cancelar") } function* actionC(payload) { console.log("=> actionC") } function* main() { // console.log("main") yield takeLatest("ACTION-A", actionA) yield takeLatest("ACTION-B", actionB) // yield takeLatest("ACTION-C", actionC) } function runGen({ iter, takers, run, gens }) { let result = iter.next(); let yield$; while (!result.done) { const yieldedValue = result.value; if (iter.cancelRequest) { return; } switch (yieldedValue.effect) { case "takeLatest": takers[yieldedValue.action] = yieldedValue break; case "put": const action = yieldedValue.action run(action) break; case "fork": const iter1 = yieldedValue.fnGenerator() yield$ = runGen({ iter: iter1, takers, run }) break; case "take": const gen = { fnGenerator: () => iter, yieldedValue }; makeGen(gen.fnGenerator) takers[yieldedValue.action] = gen return result; break; default: break; } result = iter.next(yield$); } } function createRun(saga) { const takers = {}; const gens = {}; return function run(action) { const iter = saga(); if (!Object.keys(takers).length) { runGen({ iter, takers, gens }); } const taker = takers[action]; if (taker) { const fnCall = taker.fnGenerator if (isGen(fnCall)) { const value = fnCall() runGen({ iter: value, takers, run, gens }) } if (taker.yieldedValue) { delete takers[taker.yieldedValue.action] } } console.log(takers) return iter; } } const run = createRun(main) run("ACTION-A") console.log("ACTION-CANCEL") run("ACTION-CANCEL")