Skip to content

Instantly share code, notes, and snippets.

@reem
Created October 29, 2016 01:38
Show Gist options
  • Save reem/fa45da35a41122f3cba0bb8eecafbe2d to your computer and use it in GitHub Desktop.
Save reem/fa45da35a41122f3cba0bb8eecafbe2d to your computer and use it in GitHub Desktop.
function runSaga(saga, ...args) {
const generator = saga(...args);
return execute(generator, []);
}
function* values(arr) {
for (let i = 0; i < arr.length; i++) {
yield arr[i];
}
}
function execute(generator, deferred, inject) {
const next = generator.next(inject);
return recurse(generator, deferred, next);
}
function recurse(generator, deferred, instruction) {
while (true) {
const { value: cmd, done } = instruction;
if (done) {
if (deferred.length) {
deferred.reverse();
return execute(values(deferred), []).then(() => cmd);
} else {
return Promise.resolve(cmd);
}
}
if (cmd.kind === 'run') {
const old = generator;
generator = (function* () {
const result = yield* cmd.saga();
return yield join(execute(old, deferred, result));
})();
instruction = generator.next();
} else if (cmd.kind === 'join') {
return cmd.promise.then(result => {
return execute(generator, deferred, result);
}).catch(err => {
const next = generator.throw(err);
return recurse(generator, deferred, next);
});
} else {
deferred.push(cmd.effect);
instruction = generator.next();
}
}
}
// effects
function run(saga) {
return {
kind: 'run',
saga
};
}
function call(saga, ...args) {
return run(function *() {
return yield join(runSaga(saga, ...args));
});
}
function join(promise) {
return {
kind: 'join',
promise
};
}
function defer(effect) {
return {
kind: 'defer',
effect
};
}
function fork(effect) {
return run(function* () {
const done = runSaga(function *() { yield effect; });
yield defer(join(done));
return done;
});
}
function timeout(ms) {
return run(function* () {
return yield join(new Promise(resolve => setTimeout(resolve, ms)));
});
}
module.exports = {
defer, call, join, run, runSaga, fork, timeout
};
// example
function* go() {
const result = yield call(function* () {
yield fork(timeout(2000));
yield timeout(500);
console.log('finishing');
return 'hello';
});
console.log('done waiting', result);
for (let i = 0; i < 1000; i++) {
yield run(function* () { yield join(Promise.resolve()); });
yield defer(join(Promise.resolve()));
}
}
runSaga(go);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment