Priority inversion in async code

Slap yourself if

You think async automatically respects priority because ‘the browser scheduler is smart’.

Why this exists

Priority inversion exists because async boundaries erase intent. When low-importance work accidentally blocks or delays high-importance work, responsiveness collapses even though nothing is technically ‘slow’.

Mental model

Async code runs on shared execution lanes. Priority inversion happens when low-priority work occupies a lane needed by high-priority work, forcing the important thing to wait for something that shouldn’t matter.

  • High- and low-priority tasks are scheduled onto the same queues.
  • Async continuations resume without inherent priority context.
  • Long or frequent low-priority tasks monopolize execution.
  • High-priority interactions are delayed behind irrelevant work.
  • Treating async tasks as free or parallel.
  • Running background work on the main thread during interactions.
  • Chaining promises without yielding or reprioritizing.
  • Assuming awaits preserve urgency.

Priority inversion in async code occurs when lower-priority asynchronous work blocks or delays higher-priority tasks because they share execution resources without enforced priority ordering.

  • Background sync running during user input
  • Long promise chains triggered by non-critical events
  • Shared queues for critical and non-critical work
  • Responsiveness issues without obvious long tasks

Deep dive

Requires Pro

Premium deep dives include more internals, more scars.

How async scheduling loses priority

How inversion manifests as jank

Explicit priority versus simplicity

Debugging priority inversion

When priority concerns are overkill