GoogleChromeLabs / GoogleChromeLabs/comlink
Callback proxies called at different times in Firefox depending on whether they're passed directly or set as a property
- Dominant language
- TypeScript
- Stars
- 12.8k
- Forks
- 435
- PR merge metrics
- No merged PRs in 30d
Description
`index.html`:
```html
import * as Comlink from "https://unpkg.com/comlink@alpha/dist/esm/comlink.mjs";
function callback(value) {
console.log(`Result : ${value}`);
}
async function init() {
const {MyClass} = Comlink.wrap(new Worker("worker.js"));
const c = await new MyClass(Comlink.proxy(callback));
c.run(Comlink.proxy(callback))
}
init();
```
`worker.js`:
```js
importScripts("https://unpkg.com/comlink@alpha/dist/umd/comlink.js");
class MyClass {
constructor (cb) {
this.callbackProperty = cb;
}
run(directCallback) {
this.callbackProperty("callbackProperty");
directCallback("directCallback");
console.log("Called callbacks!")
while (true) {
new Date()
}
}
}
Comlink.expose({MyClass});
```
In Chrome (and I think most other browsers) this logs everything as expected:
```
Called callbacks!
Result : callbackProperty
Result : directCallback
```
In Firefox, as long as the blocking `while (true) {` code is present, the `Result : directCallback` is missing. My interpretation of this is that `directCallback("directCallback");` queues a message to be posted back to the main thread, but that message is only to be posted after `run()` completes, which may never happen.
What's surprising is that `Result : callbackProperty` still gets logged, so the message produced by `this.callbackProperty("callbackProperty");` still gets posted either way. I can't see why at a glance - `this.callbackProperty` and `directCallback` are both proxies and I expect them to behave the same.
While I'm not using a silly looking `while (true)` in my real use case, it is still necessary to run synchronous code in my worker function after calling the callback. I can't use async, await, promises, or other callbacks. If you're really curious, the problem being solved is here: https://github.com/pyodide/pyodide/issues/1219 . In this case the worker function actually can't finish if the callback is never received by the main thread, but I imagine for other people this could manifest as the main thread not receiving progress updates to show the user while the worker does some long computation.
In any case, `directCallback` seems to work fine when testing in Chrome, and it was very hard to figure out both what was going wrong in Firefox and how to 'fix' it, so I think this difference between the two types of callback is a significant bug.
Beyond that though, I'm worried that the `callbackProperty` method only 'happens' to work in Firefox, and that I'm relying on some undefined behaviour that may change in future versions of comlink or browsers (including Firefox, Chrome, and others). Should I assume that as long as a worker function is running, messages sent in that function may not be received by the main thread?
Contributor guide
Assessment
This issue has not been assessed yet.