Why do my Web Worker results come back out of order even with a single queue?

Yo folks, I’m wiring up a Web Worker to crunch a bunch of tasks and push results back to the UI, but I’m seeing stale results land after newer ones. I’m trying to keep the main thread snappy, but I also don’t want to leak memory by keeping every pending job forever.

const worker = new Worker("worker.js");
let nextId = 0;
const pending = new Map();

export function runJob(payload) {
  const id = nextId++;
  worker.postMessage({ id, payload });
  return new Promise((resolve, reject) => {
    pending.set(id, { resolve, reject });
  });
}

worker.onmessage = (e) => {
  const { id, result } = e.data;
  const p = pending.get(id);
  if (!p) return; // sometimes this hits
  pending.delete(id);
  p.resolve(result);
};

What’s the cleanest pattern to handle backpressure + cancellation so old jobs can’t “win” and I don’t end up with a growing pending Map?