Skip to content

Instantly share code, notes, and snippets.

@CMCDragonkai
Last active June 12, 2018 14:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CMCDragonkai/01ebcdf7f51afcc94b028215a28fd2ff to your computer and use it in GitHub Desktop.
Save CMCDragonkai/01ebcdf7f51afcc94b028215a28fd2ff to your computer and use it in GitHub Desktop.
Cooperative Multitasking in JavaScript with Coroutines and Generators #javascript
// sometimes you need cooperative multitasking
// you don't want to rely on the JS event loop mechanism
// because either you're not doing any IO
// or you want to more tightly control the exact allocation
// of task computation time
// below we show 2 ways of achieving cooperative multitasking
// the first just uses normal function closures
// each time a coroutine step is done
// we return the result plus a closure that can take the next number
// while this is very flexible, this synxtax is quite verbose
// and also results in an unscalable pyramid syntax structure
// haskell's solution to this is to use the overloaded do notation!
// sidenote: don't use `let a = a + 1` or `const a = a + 1`
// JS will complain about `a` not defined
// even if you are in a function closure inheriting an environment
// with `a` already defined
function co (input) {
let result = input;
return [result, (input) => {
result = result + input;
return [result, (input) => {
result = result + input;
return [result, null];
}];
}];
}
let r1,n1,r2,n2;
// run 1
[r1, n1] = co(0);
console.log(r1);
// run 2
[r2, n2] = co(1);
console.log(r2);
// run 1
[r1, n1] = n1(0);
console.log(r1);
// run 2
[r2, n2] = n2(1);
console.log(r2);
// run 1
[r1, n1] = n1(0);
console.log(r1);
// run 2
[r2, n2] = n2(1);
console.log(r2);
// n1 and n2 are now null
console.log(n1, n2);
// JavaScript has the generator syntax
// using function* and yield and yield*
// this gives us a much more cleaner
// syntax structure at the cost of some symmetricity
// see how you the first `next()` has nothing
// passed in, this is because
// the `next()` pauses execution before input is passed
// so the very first yield's input is facilitated via
// the generator construction
function* gen(input) {
let result = input;
input = yield result;
result = result + input;
input = yield result;
result = result + input;
yield result;
}
const g1 = gen(0);
const g2 = gen(1);
console.log(g1.next());
console.log(g2.next());
console.log(g1.next(0));
console.log(g2.next(1));
console.log(g1.next(0));
console.log(g2.next(1));
// value is undefined and done is true
console.log(g1.next(), g2.next());
// what we need now are libraries
// that allow easy creation and composition of generators
// but also consumers, so you can cooperative multitasking pipes
// if you use `input = yield;`, you get the equivalent of a consumer!
// http://2ality.com/2015/03/es6-generators.html
// https://github.com/ubolonton/js-csp
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment