Interesting. Are you talking about the latency to spawn new workers, or getting data from the main thread to the worker? To give you an idea, this library uses a lazily initialized thread pool (thread-per-core by default), where tasks are shared between workers (like the Tokio library in Rust). This means workers only need to be initialized once, and passing data via structured clone is usually very fast and optimized in most engines. Better yet is to use ArrayBuffer or SharedArrayBuffer, which can be transferred or shared between threads without any serialization overhead.
It usually came from serializing and deserializing objects which here it’s a shared json buffer? But even then there’s a serialization bottleneck right? You’d have to be mindful about how the context and closures work across boundaries. Then there’s also spinning up the workers, but I suppose you could do this ahead of time. Maybe my complaint is self-inflicted and is ultimately avoidable - but the complexity begins to mount.
There’s also the queuing and blocking nature of web-workers, I wish they could asynchronously process messages the same way js IO works, but that’s not the case. Rather you are batching full units of work. The mental model is different.
Anecdotally in Firefox I must have run into some memory leak issues and had to hard restart.
Ultimately I ended up going with service workers, which yes sounds strange but I found to be much easier to work with. Cancellable requests, async, long living in the background … but maybe it just works best for me ;)
It was a design decision to make the syntax feel as familiar to Rust as possible. But I do agree that it's a bit verbose and that it won't hurt to add a .dispose() handle to the objects themselves.
I added a bit more information about Bun compatibility:
> While Bun is supported and Bun does support the `using` keyword, it's runtime automatically creates a polyfill for it whenever Function.toString() is called. This transpiled code relies on specific internal globals made available in the context where the function is serialized. Because the worker runs in a different isolated context where these globals are not registered, code with `using` will fail to execute.
Creator here. Yes it's a wrapper around the Web Worker and Node Worker Threads API. In order to create an inline worker, the user provided function is serialized using .toString() and any provided yield statements (which specify outside variables, functions & imports) are extracted. Because JavaScript objects are passed by reference, we can get the references by running the user function on the main thread first (iterating over each yield statement), and stop on the last yield so the main thread doesn't execute the rest of the function. Then, whenever a thread mutates a shared variable, the new value is send or transfered to the main thread, which then updates the variable using the object's reference.