18

Currently, a Web Worker is instantiated thus:

let worker = new Worker('worker.js');

The browser then fetches worker.js and it can start responding to messages.

I'd like to implement my worker's functionality using WebAssembly. Ideally, I'd like to do something like this:

let worker = new Worker('worker.wasm');

But I'm pretty sure that's not possible. The most obvious alternative is to have worker.js fetch worker.wasm and compile and run it. But this means we fetch one script (worker.js) whose only job is to fetch and run another script (worker.wasm). This feels gross to me. And so my question: is there a cleaner way of using WebAssembly within a Web Worker, which won't introduce an extra fetch step?

4
  • "And so my question: is there a cleaner way of using WebAssembly within a Web Worker, which won't introduce an extra fetch step?" What is purpose of using Worker in the first instance if Worker is not intended to be used? No actual problem statement exists at Question. Commented Nov 2, 2017 at 20:31
  • @guest271314 one benefit is that wasm would be run in a different thread Commented Nov 27, 2022 at 15:02
  • Probably you could put the wasm in a SharedArrayBuffer, didn't try it out but I could imagine that with a SharedArrayBuffer no copying is needed. Commented Nov 27, 2022 at 15:03
  • This repository contains a couple of examples for using web workers with Wasm (compiled from Rust): github.com/sgasse/wasm_worker_interaction Commented Jan 21, 2023 at 20:28

1 Answer 1

2

You can postMessage a WebAssembly.Module to a Worker. You'd therefore compile foo.wasm in your main script, and then postMessage it, which implementations are expected to optimize so as not to recompile or duplicate code (though at this time not all implementations do so). You then merely need your worker to instantiate.

One thing you need for instantiate is an importObject, and what you pass in needs to be resident to that worker! So even if you could say "new worker with this .wasm" you wouldn't have a way to specify the importObject.

This is documented in structured clone, which also affects IndexDB.

Sign up to request clarification or add additional context in comments.

5 Comments

I'm not sure this actually works. When I try to send a wasm Module in postMessage I get this: example.js:54 Uncaught (in promise) DOMException: Failed to execute 'postMessage' on 'Worker': () => resolve(Module) could not be cloned. at localhost:8000/example.js:13702:31 at <anonymous>
I cleaned up my code and am using WebAssembly.compile to produce a module. I then try to send it via postMessage but I get this: Uncaught (in promise) DOMException: Failed to execute 'postMessage' on 'Worker': An object could not be cloned.
That was under Chrome 60. Chrome 62 gives Uncaught (in promise) DOMException: Failed to execute 'postMessage' on 'Worker': #<Module> could not be cloned. Firefox 57.0b14 seems to work.
That sounds like a Chrome bug.
github.com/nodeca/pica/blob/3.0.6/index.js#L322 wasm object transfer worked for me in chrome. But i dropped this in next version of package. Browserify + webworkify are good enougth (it creates ww src on the fly from modules in main thread). IMHO additional compile step in ww for small modules is cheap and preferable to keep things simple.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.