Why does my worker keep sending results after I cancel the job?

What’s up everyone? I’m trying to offload some heavy parsing to a Web Worker while keeping the UI responsive, but I’m hitting a nasty failure mode where “canceled” work still posts results back later and overwrites newer state.

const worker = new Worker("/parseWorker.js");
let currentJobId = 0;

export function parseAsync(text) {
  const jobId = ++currentJobId;
  worker.postMessage({ jobId, text });

  return new Promise((resolve) => {
    worker.addEventListener("message", (e) => {
      if (e.data.jobId !== jobId) return; // ignore stale
      resolve(e.data.result);
    });
  });
}

export function cancelAll() {
  currentJobId++; // invalidate
}

Am I leaking listeners / creating a race here, and what’s the pragmatic pattern to do cancellation + backpressure with a single long-lived worker without stale results clobbering the UI state?

1 Like