GoogleChromeLabs / comlink

Comlink makes WebWorkers enjoyable.
Apache License 2.0
11k stars 382 forks source link

AbortController AbortSignal Cancellation Token #615

Closed qwtel closed 1 year ago

qwtel commented 1 year ago

Leaving this here for future search: Comlink, AbortController, AbortSignal, Cancellation Token.

A transfer handler that sends an AbortSignal across the chasm. It's not a proxy, but a copy that aborts when the original aborts.

const signalFinalizers = "FinalizationRegistry" in globalThis
  ? new FinalizationRegistry(async (port: MessagePort) => {
    port.postMessage(null)
    port.close();
  })
  : undefined;

Comlink.transferHandlers.set("abortsignal", {
  canHandle(value) {
    return value instanceof AbortSignal || value?.constructor?.name === "AbortSignal";
  },
  serialize(signal) {
    if (signal.aborted) 
      return [{ aborted: true }];

    const { port1, port2 } = new MessageChannel();
    signal.addEventListener(
      "abort", 
      () => port1.postMessage({ reason: signal.reason }), 
      { once: true }
    );

    signalFinalizers?.register(signal, port1);

    return [{ aborted: false, port: port2 }, [port2]];
  },
  deserialize({ aborted, port }) {
    if (aborted || !port)
      return AbortSignal.abort();

    const ctrl = new AbortController()

    port.addEventListener("message", ev => {
      if (ev.data && "reason" in ev.data)
        ctrl.abort(ev.data.reason);
      port.close();
    }, { once: true });

    port.start();

    return ctrl.signal;
  }
} as Comlink.TransferHandler<AbortSignal, { aborted: boolean, port?: MessagePort }>);
alexgleason commented 8 months ago

Leaving this here for future search: Comlink, AbortController, AbortSignal, Cancellation Token.

You sir, are an absolute boss.

kernelwhisperer commented 6 months ago

Amazing!