v153 · loaf in workers

The workaround, and what it cannot tell you

There is a way to notice a blocked worker from inside it: reschedule a task continuously and watch for one that runs late. It works, it costs almost nothing, and comparing what it produces against a real Long Animation Frame entry shows exactly what is missing.

Block the worker, then compare the two records

What the worker's self-timing noticed
#blocked forat
Not run yet.
Press the button.

The self-timer is nine lines: a setTimeout(…, 0) that reschedules itself and records any gap over 50ms. That is the entire workaround, and its total cost is one task per turn of the loop.

Field by field

A real long-animation-frame entry against what a self-timer can produce
fieldthe entrythe workaroundwhy it matters

The workaround in full

// Inside the worker.
let lastTaskEnd = performance.now();
const tick = () => {
  const now = performance.now();
  const gap = now - lastTaskEnd;
  if (gap > 50) report({ blockedFor: gap, at: now });
  lastTaskEnd = performance.now();
  setTimeout(tick, 0);
};
setTimeout(tick, 0);

Note what it measures: the gap between one of its own tasks and the next. If a single task blocks for 400ms, the gap is 400ms and the timer is correct. If four tasks each block for 100ms with the timer running in between, the timer reports nothing at all — every individual gap is under the threshold, and the worker was still unresponsive for 400ms.

see also