Skip to content

Instantly share code, notes, and snippets.

@IUnknown68
Last active May 19, 2019 12:29
Show Gist options
  • Save IUnknown68/8041a9ef25ef8609607f22cb1ca6ac22 to your computer and use it in GitHub Desktop.
Save IUnknown68/8041a9ef25ef8609607f22cb1ca6ac22 to your computer and use it in GitHub Desktop.
Cooperative multitasking for javascript
function multiTasking(schedule = setTimeout) {
const taskList = new Set();
let isRunning = false;
let isScheduled = false;
const next = () => {
isScheduled = false;
taskList.forEach(task => {
if (!isRunning) {
return;
}
if (task.next().done) {
remove(task);
}
});
if (isRunning && taskList.size) {
run();
} else {
stop();
}
};
const run = () => {
if (!isScheduled) {
isScheduled = true;
console.log('scheduling');
schedule(next);
}
}
const start = () => {
if (!isRunning) {
isRunning = true;
console.log('starting');
run();
}
};
const stop = () => {
console.log('stopped');
isRunning = false;
};
const add = (...tasks) => {
tasks.forEach(task => {
taskList.add(task);
start();
});
return tasks.length > 1 ? tasks : tasks[0];
};
const remove = (...tasks) => {
tasks.forEach(task => {
taskList.delete(task);
});
};
const clear = () => {
taskList.clear();
};
return {
start,
stop,
add,
remove,
clear
};
}
@IUnknown68
Copy link
Author

Each task needs to be a generator function that yields control back to the task manager (cooperative multitasking):

function* task1() {
  while(true) {
    // do some work, then
    yield;
  }
}

You can pass a custom scheduler function, e.g. one that runs always one second after the last run:

const timeoutScheduler = (timeout) => (next) => setTimeout(next, timeout);
const tm = multiTasking(timeoutScheduler(1000));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment