I have a cellular automaton which we can abbreviate like this:
// pretend slow update function called every tick of the metronome
const update = () => {
let i = 0
while (i < 10000) {
console.log(i)
i++
}
}
Then I have in the main thread a Tone.js "loop" running every tick of the metronome:
new Tone.Loop(time => {
// update() in worker
// then draw() in main thread
}, '4n').start(0)
This loop essentially runs every quarter note at 240 BPM. You can approximate it with setTimeout, but with some extra fancy logic around keeping track of the elapsed time.
My question is, what is the architecture to make sure this draws every tick of the beat and doesn't get out of sync?
If I do this in the web worker system, then I am not sure how it will behave:
// main.js
worker.onmessage = () => draw()
new Tone.Loop(time => worker.postMessage('update'), '4n').start(0)
// worker.js
worker.onmessage = () => {
update()
postMessage("draw")
}
Depending on the async nature of how long the postMessage takes in both directions, the draw will come way after the beat potentially.
How do I do this correctly, architecture wise?
Note, the drawing to canvas must happen in the main thread, while the update function of the (multiple instances of) cellular automata must be updated all at once in the worker, for performance. Then there will be a SharedArrayBuffer to read the final computed values in the main.js.
What is the general approach I should take to wire this up?