Skip to content

Commit 9181fa5

Browse files
Merge pull request #3 from foxglove/achim/performance-single-message-handler-rebased
Use a single "message" event listener to dispatch received messages
2 parents 3aead4f + 3d1a58c commit 9181fa5

File tree

1 file changed

+37
-14
lines changed

1 file changed

+37
-14
lines changed

src/comlink.ts

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,10 @@ interface ThrownValue {
227227
type SerializedThrownValue =
228228
| { isError: true; value: Error }
229229
| { isError: false; value: unknown };
230+
type PendingListenersMap = Map<
231+
string,
232+
(value: WireValue | PromiseLike<WireValue>) => void
233+
>;
230234

231235
/**
232236
* Internal transfer handler to handle thrown exceptions.
@@ -392,7 +396,26 @@ function closeEndPoint(endpoint: Endpoint) {
392396
}
393397

394398
export function wrap<T>(ep: Endpoint, target?: any): Remote<T> {
395-
return createProxy<T>(ep, [], target) as any;
399+
const pendingListeners : PendingListenersMap = new Map();
400+
401+
ep.addEventListener("message", function handleMessage(ev: Event) {
402+
const { data } = ev as MessageEvent;
403+
if (!data || !data.id) {
404+
return;
405+
}
406+
const resolver = pendingListeners.get(data.id);
407+
if (!resolver) {
408+
return;
409+
}
410+
411+
try {
412+
resolver(data);
413+
} finally {
414+
pendingListeners.delete(data.id);
415+
}
416+
});
417+
418+
return createProxy<T>(ep, pendingListeners, [], target) as any;
396419
}
397420

398421
function throwIfProxyReleased(isReleased: boolean) {
@@ -402,7 +425,7 @@ function throwIfProxyReleased(isReleased: boolean) {
402425
}
403426

404427
function releaseEndpoint(ep: Endpoint) {
405-
return requestResponseMessage(ep, {
428+
return requestResponseMessage(ep, new Map(), {
406429
type: MessageType.RELEASE,
407430
}).then(() => {
408431
closeEndPoint(ep);
@@ -447,6 +470,7 @@ function unregisterProxy(proxy: object) {
447470

448471
function createProxy<T>(
449472
ep: Endpoint,
473+
pendingListeners: PendingListenersMap,
450474
path: (string | number | symbol)[] = [],
451475
target: object = function () {}
452476
): Remote<T> {
@@ -458,20 +482,21 @@ function createProxy<T>(
458482
return () => {
459483
unregisterProxy(proxy);
460484
releaseEndpoint(ep);
485+
pendingListeners.clear();
461486
isProxyReleased = true;
462487
};
463488
}
464489
if (prop === "then") {
465490
if (path.length === 0) {
466491
return { then: () => proxy };
467492
}
468-
const r = requestResponseMessage(ep, {
493+
const r = requestResponseMessage(ep, pendingListeners, {
469494
type: MessageType.GET,
470495
path: path.map((p) => p.toString()),
471496
}).then(fromWireValue);
472497
return r.then.bind(r);
473498
}
474-
return createProxy(ep, [...path, prop]);
499+
return createProxy(ep, pendingListeners, [...path, prop]);
475500
},
476501
set(_target, prop, rawValue) {
477502
throwIfProxyReleased(isProxyReleased);
@@ -480,6 +505,7 @@ function createProxy<T>(
480505
const [value, transferables] = toWireValue(rawValue);
481506
return requestResponseMessage(
482507
ep,
508+
pendingListeners,
483509
{
484510
type: MessageType.SET,
485511
path: [...path, prop].map((p) => p.toString()),
@@ -492,17 +518,18 @@ function createProxy<T>(
492518
throwIfProxyReleased(isProxyReleased);
493519
const last = path[path.length - 1];
494520
if ((last as any) === createEndpoint) {
495-
return requestResponseMessage(ep, {
521+
return requestResponseMessage(ep, pendingListeners, {
496522
type: MessageType.ENDPOINT,
497523
}).then(fromWireValue);
498524
}
499525
// We just pretend that `bind()` didn’t happen.
500526
if (last === "bind") {
501-
return createProxy(ep, path.slice(0, -1));
527+
return createProxy(ep, pendingListeners, path.slice(0, -1));
502528
}
503529
const [argumentList, transferables] = processArguments(rawArgumentList);
504530
return requestResponseMessage(
505531
ep,
532+
pendingListeners,
506533
{
507534
type: MessageType.APPLY,
508535
path: path.map((p) => p.toString()),
@@ -516,6 +543,7 @@ function createProxy<T>(
516543
const [argumentList, transferables] = processArguments(rawArgumentList);
517544
return requestResponseMessage(
518545
ep,
546+
pendingListeners,
519547
{
520548
type: MessageType.CONSTRUCT,
521549
path: path.map((p) => p.toString()),
@@ -595,22 +623,17 @@ function fromWireValue(value: WireValue): any {
595623

596624
function requestResponseMessage(
597625
ep: Endpoint,
626+
pendingListeners: PendingListenersMap,
598627
msg: Message,
599628
transfers?: Transferable[]
600629
): Promise<WireValue> {
601630
return new Promise((resolve) => {
602631
const id = Math.trunc(Math.random() * Number.MAX_SAFE_INTEGER).toString();
603-
ep.addEventListener("message", function l(ev: MessageEvent) {
604-
if (!ev.data || !ev.data.id || ev.data.id !== id) {
605-
return;
606-
}
607-
ep.removeEventListener("message", l as any);
608-
resolve(ev.data);
609-
} as any);
632+
pendingListeners.set(id, resolve);
610633
if (ep.start) {
611634
ep.start();
612635
}
613636
ep.postMessage({ id, ...msg }, transfers);
614-
});
637+
});
615638
}
616639

0 commit comments

Comments
 (0)