Context switching in JavaScript
A generator function pauses at every yield and resumes when you call next() — just like a process that's switched out and back in. Cooperative multitasking (early Mac OS, Windows 3.1 — and JavaScript's own event loop) works exactly this way: programs run until they *choose* to give up the CPU.
function runAll(programs) {
const ready = Object.entries(programs).map(([name, program]) => ({ name, it: program() }));
const log = [];
while (ready.length) {
const p = ready.shift(); // pick the next process
const { value, done } = p.it.next(); // let it run until it yields
if (done) {
log.push(`${p.name} exited`);
continue;
}
log.push(`${p.name}: ${value}`);
ready.push(p); // back of the queue: a context switch
}
return log;
}Generators as paused processes
This project turns an abstract idea — saving and restoring a process — into a few lines of JavaScript you can step through, which makes the next lessons on preemption and kernels much easier to picture.
A generator object remembers exactly where it stopped and the values of its local variables, just as a kernel saves a process's registers and program counter. Calling next() resumes it until the next yield, which hands a value back — like a process making a system call. When the function returns, next() reports done: true: the process has terminated.
function* counter(name) {
for (let i = 1; i <= 3; i++) yield `${name} ${i}`;
}
const p = counter("A");
console.log(p.next().value);
console.log(p.next().value);