Skip to content

Instantly share code, notes, and snippets.

@makakoa
Last active August 25, 2023 03:18
Show Gist options
  • Save makakoa/f898f32840d1a6d27c37e20240054081 to your computer and use it in GitHub Desktop.
Save makakoa/f898f32840d1a6d27c37e20240054081 to your computer and use it in GitHub Desktop.
Chunking heavy JS workloads with generator functions (function*)
const nth = 1000000;
console.time("fib");
chunkWork(fibonacciDigits(nth)).then((digits) => {
console.log("The ", nth, " fibonacci number has ", digits, " digits");
console.timeEnd("fib");
});
function chunkWork(workGenerator, minChunkTime = 50) {
return new Promise((resolve) => {
function processChunk() {
let start = Date.now();
let status = null;
while (Date.now() - start < minChunkTime) {
status = workGenerator.next();
if (status.done) break;
}
if (status.done) {
resolve(status.value);
} else {
setTimeout(processChunk, 0);
}
}
processChunk();
});
}
function* fibonacciDigits(n) {
let count = 0n;
let a = 0n;
let b = 1n;
// Stop at a million bc it gets really big
while (count < n) {
count = count + 1n;
let c = a + b;
a = b;
b = c;
yield;
}
return b.toString().length;
}

This is a little example of chunking computational loops with generator functions to allow JS threads to remain mostly unblocked.

Some notes on this example:

  • This example uses a time threshold for yielding back to the event loop but it could easily be a loop iterations threshold
  • This also only yields the final product as a promise but could easily be a subscription
  • We use a wrapping functional loop (processChunk) to allow queueing more work to the event loop, but inside of that I opt for a while loop because a direct recursive loop can easily exceed call stack size limits in timeboxed execution loops.

You can see a similar example with multiple available computations plugged into the React lifecycle: https://codepen.io/makakoa/pen/qBLONVb

Is this better than a service worker?

Probably not for most cases. Since this doesn't utilize separate threads there is non-zero impact to the parent thread. But some potential benefits are not relying on service worker support, being able to run parallel computations, and just living a little closer to whatever might be interested in the results.

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