← Recipes

阅读中文版本

Debounce ResizeObserver Layout Work

Throttle layout work triggered by ResizeObserver so rapid resizes do not thrash the main thread.

~25 minfrontendperformancejavascript

Task

Wrap expensive resize handling so it runs at most once per animation frame.

When to use this

A chart recalculates on every resize event, freezing the page while the window is dragged.

Prerequisites

  • A component using ResizeObserver
  • Expensive layout computation
  • A browser to profile

Steps

1. Schedule recalculation on the next animation frame.

let scheduled = false;
const observer = new ResizeObserver(() => {
  if (scheduled) return;
  scheduled = true;
  requestAnimationFrame(() => {
    scheduled = false;
    recomputeLayout();
  });
});
observer.observe(container);

Expected output: Layout work runs at most once per frame regardless of observer frequency.

2. Verify only one recalculation per frame.

performance.mark('layout');
// count marks during a resize drag and confirm they match frame count

Expected output: Mark count matches frames, not raw resize events.

Troubleshooting

Problem

ResizeObserver loop warnings

Solution

Do not mutate the observed element size synchronously inside the callback.

Problem

Missing final resize

Solution

Trailing debounce ensures the last size is applied.

Limitations

  • Animation-frame scheduling still runs during scrolling.
  • Does not reduce the cost of a single computation.
  • Observer loops must be avoided.

What this recipe does

Wrap expensive resize handling so it runs at most once per animation frame.

A chart recalculates on every resize event, freezing the page while the window is dragged.

Prerequisites

  • A component using ResizeObserver
  • Expensive layout computation
  • A browser to profile

Procedure

  1. Schedule recalculation on the next animation frame.
let scheduled = false;
const observer = new ResizeObserver(() => {
  if (scheduled) return;
  scheduled = true;
  requestAnimationFrame(() => {
    scheduled = false;
    recomputeLayout();
  });
});
observer.observe(container);

Expected result: Layout work runs at most once per frame regardless of observer frequency.

  1. Verify only one recalculation per frame.
performance.mark('layout');
// count marks during a resize drag and confirm they match frame count

Expected result: Mark count matches frames, not raw resize events.

How to confirm it worked

Run the commands above and confirm every expected result in order. If a step does not produce the stated output, use the troubleshooting notes before continuing. A passing run shows profiling shows recalculation tied to frame rate, not to raw resize events, and the final size is correct.

Troubleshooting

ResizeObserver loop warnings — Do not mutate the observed element size synchronously inside the callback.

Missing final resize — Trailing debounce ensures the last size is applied.

Limitations

  • Animation-frame scheduling still runs during scrolling.
  • Does not reduce the cost of a single computation.
  • Observer loops must be avoided.