GoogleChromeLabs / GoogleChromeLabs/comlink
Expose and wrap a worker at once
- Dominant language
- TypeScript
- Stars
- 12.8k
- Forks
- 435
- PR merge metrics
- No merged PRs in 30d
Description
Hi,
I am trying to create two-way communication between two web workers, both using 'Comlink Proxy's using a single `MessageChannel`.
Let's say that I have a worker running. At some point, I want to spin up a new instance of the same worker and want them to be able to communicate with each other. Since it's just a new instance, they have the exact same API.
My idea was to create a `MessageChannel` in the main thread and pass a port to the two workers. They could then both `Comlink.wrap` on that port to call the other worker and also expose themselves to the same port.
worker.js
```
// called by main thread
connectToWorker: (port, expose, id) => {
Comlink.expose(workerAPI, port);
// Wrap around the port so I can send a message to the other worker
otherWorkerProxy = Comlink.wrap(port);
otherWorkerProxy.foo(id, 'Hi');
},
```
This fails however with the following message:
```
comlink.js:123 Uncaught (in promise) DOMException: Failed to execute 'postMessage' on 'MessagePort': (workerId, message) => {
console.log(`Message from ${workerId}: ${message}`)
} could not be cloned.
at https://unpkg.com/comlink@4.2.0/dist/umd/comlink.js:123:18
```
I took a little time into investigating why this happens and it actually makes sense. If you call `expose`, you register an `eventListener` for `message` on the port. If you call a function on a `proxy` in the worker, it also registers a listener for `message`.
If I do both of these actions in the same worker, this means, that there are two listeners, one because of `expose` and one cause we just called a function on the proxy (which uses the same MessagePort). If the result of calling that function arrives, it will be passed to the `message` listener from `expose`. Which doesn't handle this properly and eventually results in this error.
I am aware that you can register callbacks from one worker to the other to make this work. But, since both of my workers are the exact same js file, I'd prefer to not do that. Looking at the code, it should actually be fairly simple to fix. Make the `expose` message handler ignore those messages if needed. I'd be more than happy to create a PR for this.
**Is there an easier way to do this? Am I missing something?
If not, would you consider a PR for this.**
I made a repro where you can see this right here: https://github.com/KwintenP/comlink-worker-repro. Comment out line 23 and in 25 from index.js to see the error.
Thanks!
Contributor guide
Assessment
This issue has not been assessed yet.