GoogleChromeLabs / GoogleChromeLabs/comlink
Feature request: Automatically reject pending requests when proxy is released
- Dominant language
- TypeScript
- Stars
- 12.8k
- Forks
- 435
- PR merge metrics
- No merged PRs in 30d
Description
As it stands (as far as I can tell) comlink does not reject previous requests when closed, so if a proxy is released while you are waiting on a response to a previous call, there is no error, the promise just never resolves. There's no real way to deal with this outside of comlink except to track the state of the worker manually and add something to every function call to reject pending requests when the worker is closed.
Would be fairly simple to add by doing the following:
- When postMessage is called, add the reject(e) callback from the promise to an array.
- Remove this callback from the array on completion.
- When the proxy is released, loop over the array and call all of the rejection callbacks with an error message.
```
function requestResponseMessage(
ep: Endpoint,
msg: Message,
transfers?: Transferable[],
rejectors: ((e: unknown) => void)[], **<-- ADD**
): Promise {
return new Promise((resolve, reject) => { **<-- ADD**
rejectors.push(reject) **<-- ADD**
const id = generateUUID();
ep.addEventListener("message", function l(ev: MessageEvent) {
if (!ev.data || !ev.data.id || ev.data.id !== id) {
return;
}
ep.removeEventListener("message", l as any);
resolve(ev.data);
rejectors.splice(rejectors.indexOf(reject), 1) **<-- ADD**
} as any);
if (ep.start) {
ep.start();
}
ep.postMessage({ id, ...msg }, transfers);
});
}
```
```
function createProxy(
ep: Endpoint,
path: (string | number | symbol)[] = [],
target: object = function () {}
): Remote {
let isProxyReleased = false;
let rejectors = new Array<(e: unknown) => void>() **<-- ADD**
const proxy = new Proxy(target, {
get(_target, prop) {
throwIfProxyReleased(isProxyReleased);
if (prop === releaseProxy) {
return () => {
rejectors.forEach(rejector => rejector("This proxy has been released.")) **<-- ADD**
return requestResponseMessage(ep, {
type: MessageType.RELEASE,
path: path.map((p) => p.toString()),
}).then(() => {
closeEndPoint(ep);
isProxyReleased = true;
});
};
}
```
Of course anytime requestResponseMessage is called, the rejectors array would need to be passed (didnt bother to include).
Contributor guide
Assessment
This issue has not been assessed yet.