Skip to content

Instantly share code, notes, and snippets.

@greggman
Created July 3, 2019 09:32
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 greggman/a9ce4e7bac91526b62f67cdab5c3307e to your computer and use it in GitHub Desktop.
Save greggman/a9ce4e7bac91526b62f67cdab5c3307e to your computer and use it in GitHub Desktop.
Coroutine runner
function* waitSeconds(duration) {
while (duration > 0) {
duration -= globals.deltaTime;
yield;
}
}
function* waitFrames(numFrames) {
while (numFrames > 0) {
--numFrames;
yield;
}
}
class CoRoutineRunner {
constructor() {
this.generatorStacks = [];
this.addQueue = [];
this.removeQueue = new Set();
}
get isBusy() {
return this.addQueue.length + this.generatorStacks.length > 0;
}
add(generator, delay = 0) {
const genStack = [generator];
if (delay) {
genStack.push(waitSeconds(delay));
}
this.addQueue.push(genStack);
}
remove(generator) {
this.removeQueue.add(generator);
}
update() {
this._addQueued();
this._removeQueued();
for (const genStack of this.generatorStacks) {
const main = genStack[0];
// Handle if one coroutine removes another
if (this.removeQueue.has(main)) {
continue;
}
while (genStack.length) {
const topGen = genStack[genStack.length - 1];
const {value, done} = topGen.next();
if (done) {
if (genStack.length === 1) {
this.removeQueue.add(topGen);
break;
}
genStack.pop();
} else if (value) {
genStack.push(value);
} else {
break;
}
}
}
this._removeQueued();
}
_addQueued() {
if (this.addQueue.length) {
this.generatorStacks.splice(this.generatorStacks.length, 0, ...this.addQueue);
this.addQueue = [];
}
}
_removeQueued() {
if (this.removeQueue.size) {
this.generatorStacks = this.generatorStacks.filter(genStack => !this.removeQueue.has(genStack[0]));
this.removeQueue.clear();
}
}
}
function* test02() {
console.log('Go');
yield;
console.log('Gogo');
yield waitFrames(3);
console.log('Gogo2');
yield waitFrames(3);
}
function* test01() {
console.log('hello');
yield;
console.log('world');
yield test02();
console.log('!');
}
console.log('start');
const runner = new CoRoutineRunner();
runner.add(test01());
let count = 0;
while (runner.isBusy) {
console.log('---------:', count++);
runner.update();
if (count > 50) {
break;
}
}
console.log('end');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment