almessadi.
Retour à l'index

Le thrashing de mise en page commence lorsque les lectures et écritures du DOM s'opposent_

Les API de géométrie comme `getBoundingClientRect()` sont utiles, mais elles deviennent coûteuses lorsque le code force à plusieurs reprises une nouvelle mise en page au milieu des mises à jour de style et du DOM.

Publié10 décembre 2024
Temps de lecture6 min read

Le navigateur souhaite regrouper le calcul des styles et le travail de mise en page. Les problèmes de performance apparaissent lorsque le code de l'application interrompt constamment ce plan en alternant écritures et lectures du DOM dans des boucles serrées.

Ce motif est généralement appelé thrashing de mise en page.

Le Motif de Bugs

Voici la forme coûteuse :

for (const item of items) {
  item.style.width = "200px";
  const rect = item.getBoundingClientRect();
  item.style.height = `${rect.width}px`;
}

Chaque appel à getBoundingClientRect() peut forcer le navigateur à vider le travail de mise en page en attente avant de pouvoir répondre. Si cela se produit pendant le défilement, le redimensionnement ou l'animation, l'interface utilisateur devient rapidement saccadée.

Meilleur Motif

Regroupez d'abord les lectures. Regroupez ensuite les écritures :

const widths = items.map((item) => item.getBoundingClientRect().width);

items.forEach((item, index) => {
  item.style.width = "200px";
  item.style.height = `${widths[index]}px`;
});

Ce n'est pas la seule solution possible, mais cela montre la règle sous-jacente : évitez de forcer le navigateur à recalculer en continu la mise en page à l'intérieur d'un code sensible aux trames.

Quand Cela a-t-il Réellement de l'Importance

Vous le ressentez généralement dans :

  • les gestionnaires de défilement
  • les boucles d'animation
  • les interactions de glisser-déposer
  • les grandes listes avec manipulation directe du DOM

Le navigateur est rapide lorsque vous le laissez regrouper le travail. Cela devient coûteux lorsque vous le contraignez à répondre immédiatement à des questions de géométrie après chaque écriture.

Si le code doit s'exécuter pendant une animation ou une interaction, requestAnimationFrame est souvent le bon endroit pour planifier le travail de DOM regroupé afin que les lectures et les écritures se produisent dans une limite de trame plus prévisible.

Lectures Supplémentaires