I am building a tiny library that interfaces with the Canvas API through functional means.
Some functions may take too long – either due to their complexity – or a programming error (infinite loop).
If possible, how would I be able to detect that the main thread is being blocked?
Obviously JavaScript is single-threaded so is there a way to go around this?
I never had experience with Web Workers, this primary issue needs to be resolved as I’m writing a small benchmark utility (for development) and it needs to terminate a task if it exceeds a certain execution time threshold. A while loop with a counter can’t help here if the function gets into an infinite loop (right?)
JavaScript is single-threaded, I’m assuming Web Workers could resolve the problem I’m facing outlined above.
My experience with Web Workers is limited, and don’t know how easy it is to apply to resolve the problem.
2
Answers
You can measure how much time has passed since the beginning of the operation using a Date object, and if this time exceeds the allowable time (which you define yourself), then complete the operation. I have attached a simplified example, but it is important to understand the idea itself and create something more complex on top of it. You can also break a complex task into steps that will be executed in a macrotask queue (setTimeout, e.t.c.) that will not block the main thread (look for articles on how to implement this)
You can offload work to web workers, but think of them more as a separate process than another thread – your comminication with a web worker will be via messages.
You can use OffscreenCanvas to transfer the canvas data to a worker, do your work there and then transfer it back and display in your canvas element.
Regarding this feature, I remember it being temporarily disabled for security reasons, I am not sure if that is still the case. You can still convert canvas data to
UintArray
but you’d have to reimplement all image drawing ops for the worker.As for stuck operation, your solution here would be:
Do not kill and restart the worker every time, it takes considerable time to start it (tenths of a second). And always keep in mind that you want to only delegate long tasks – sending messages to workers is very fast, but not instant.
I once made a canvas animation that renders gravity simulation and uses as many workers as there are CPUs to render sections of the screen and it worked fine, so you can expect real time framerate and you can also consider splitting the work across multiple CPUs.
To answer how easy it is: you need to be able to split your task in clear independent steps that have input arguments and an output to convert this to incoming and outgoing message for the worker. You cannot share any global variables, so everything needs to be sent to the worker.