Optimisation du rendu du navigateur pour l'optimisation des performances front-end

Annuaire d'articles

introduction

À l’ère actuelle du développement rapide d’Internet, les utilisateurs ont des exigences de plus en plus élevées en matière de vitesse et de performances de chargement des pages Web. En tant que développeurs front-end, nous devons prêter attention et travailler à l’amélioration des performances de chargement et de rendu des pages Web afin d’offrir une meilleure expérience utilisateur. L'optimisation du rendu du navigateur est la clé pour atteindre cet objectif. Dans cet article, nous discuterons de quelques conseils et stratégies sur l'optimisation du rendu du navigateur, dans le but de vous aider à optimiser le processus de rendu des pages Web et à améliorer la vitesse et les performances de chargement des pages. Que vous débutiez en tant que développeur front-end ou développeur expérimenté, cet article vous fournira de précieux conseils et astuces pratiques pour que vos pages Web s'affichent plus rapidement dans le navigateur. Explorons ensemble comment améliorer les performances des pages Web grâce à l'optimisation du rendu du navigateur !

1. Processus de rendu du navigateur

Le processus de rendu du navigateur fait référence au processus dans lequel le navigateur analyse, présente, dessine et enfin affiche à l'utilisateur des ressources telles que HTML, CSS et JavaScript obtenues du serveur . Voici un organigramme simple du rendu du navigateur :

  1. Analyse HTML : le navigateur analyse HTMLle document à partir du haut, en créant une DOMarborescence (Document Object Model). DOML'arborescence représente HTMLla structure du document, y compris les balises, les attributs et les nœuds de texte.

  2. Analyse CSS : Le navigateur analyse le CSSfichier externe et applique les règles de style aux DOMéléments correspondants dans l'arborescence. Le processus d'analyse CSSproduit une arborescence CSSOM( modèle d'objet), qui est similaire à une arborescence mais représente des informations de style.CSSDOMCSS

  3. Construire un arbre de rendu (Render Tree) : Le navigateur fusionne DOMl'arborescence et CSSOMl'arborescence pour construire un arbre de rendu. L'arbre de rendu ne contient que les éléments visibles qui doivent être affichés dans la page, par exemple les éléments invisibles (par exemple display:none) ne seront pas inclus dans l'arbre de rendu.

  4. Mise en page : le navigateur calcule la taille et la position de chaque élément dans l'arborescence de rendu sur la page et détermine Box Modelles informations sur leur modèle de boîte ( ). Ce processus est appelé layout ou reflow( reflow), et il calcule la position exacte de chaque élément en fonction de certaines CSSpropriétés (telles que etc.).width、height、position

  5. Draw (Paint) : Le navigateur commence à dessiner chaque élément à l'écran en fonction des informations de l'arbre de rendu et de la mise en page. Le processus de dessin convertit chaque élément en une ou plusieurs couches et utilise GPUdes techniques d'accélération pour améliorer les performances.

  6. Rastérisation : une fois le dessin terminé, le navigateur découpe le calque en petites tuiles et les convertit en bitmaps. Ce processus est appelé rastérisation et convertit les graphiques en pixels pouvant être affichés à l'écran.

  7. Composition : Le navigateur compose toutes les tuiles dans le bon ordre et affiche le résultat final du rendu. Ce processus est appelé composition et dessine le bitmap à l'écran, mettant constamment à jour le rendu en fonction de l'interaction de l'utilisateur.

L’ensemble du processus peut être représenté sous la forme d’un organigramme comme suit :

开始 -> 解析HTML -> 样式计算 -> 布局计算 -> 绘制 -> 合成 -> 结束

En résumé, le processus de rendu du navigateur comprend des étapes telles que l'analyse HTML, l'analyse CSS, la création d'une arborescence de rendu, la mise en page, le dessin, la rastérisation et la composition. Ces étapes convertissent HTML、CSSet JavaScriptconvertissent les pages Web en contenu Web visible, permettant aux utilisateurs de naviguer normalement sur le Web.

在这里补充一点
Dans la dernière étape du processus de rendu du navigateur, Composition effectue principalement le travail suivant :

  1. Synthétiser l'arbre de rendu : le moteur de composition combinera les éléments de la page en un ou plusieurs calques en fonction des informations sur la structure et les attributs de style de l'arbre de rendu. Ces couches peuvent être dessinées et composées indépendamment comme vous le souhaitez.

  2. Dessin de calque : lors de la phase de composition, le moteur de composition dessinera chaque couche séparément dans un bitmap. Ce processus se déroule généralement dans le GPU, profitant des capacités d'accélération matérielle pour accélérer le dessin.

  3. Composition des calques : Le moteur de composition synthétise les calques dessinés dans le bon ordre. Le processus de composition effectuera des opérations telles que le mélange de transparence et le masquage sur des bitmaps de différentes couches, et générera enfin un bitmap global à afficher.

  4. Affichage et mise à jour de la liste d'affichage : Enfin, le moteur de composition envoie le bitmap global généré à l'affichage via le pipeline d'affichage pour l'affichage. Dans le même temps, le moteur de composition met à jour la liste d'affichage de la page pour refléter le dernier rendu.

En bref, la composition ( Composition) est la dernière étape du processus de rendu du navigateur, qui comprend des étapes telles que la synthèse de l'arbre de rendu, le dessin et la composition des calques, la génération du bitmap final et la mise à jour de la liste d'affichage, et enfin l'affichage du résultat du rendu sur le l'utilisateur est sur l'écran. Ces efforts contribuent à améliorer les performances de rendu et l’expérience utilisateur.

2. Reflux

1. Qu'est-ce que la refusion

La redistribution fait référence au restituement par le navigateur d'une partie ou de la totalité de la mise en page. Lorsque la structure, le style ou les propriétés de mise en page de la page changent, le navigateur déclenche la redistribution.

La redistribution se produit pendant la phase de mise en page du rendu du navigateur. Il y a deux étapes principales dans le processus de rendu : la mise en page et la peinture.

L'étape de mise en page signifie que le navigateur calcule la position et la taille de chaque élément sur la page en fonction du modèle de boîte de l'élément, établit la relation entre les éléments et génère une arborescence de mise en page (arbre de rendu). Lorsque le navigateur constate que la structure ou le style de la page a changé pendant la phase de mise en page, il déclenche une redistribution.

Pendant le processus de redistribution, le navigateur parcourt l'arborescence de mise en page, calcule la position et la taille de chaque élément et met à jour les informations de rendu correspondantes, puis régénère l'arborescence de mise en page et l'arborescence de dessin, et enfin dessine.

Il convient de noter que la redistribution est une opération relativement gourmande en performances, car lorsque la redistribution se produit, le navigateur doit recalculer la mise en page et mettre à jour les informations de rendu associées. Les redistributions fréquentes entraîneront une dégradation des performances de la page. L'apparition de redistributions doit donc être minimisée pendant le développement afin d'améliorer les performances de la page.

2. Quelles opérations peuvent provoquer un reflux

La redistribution du rendu du navigateur (redistribution) signifie que lorsque la mise en page et les propriétés géométriques changent, le navigateur recalcule la disposition des éléments et les redessine, ce qui consomme beaucoup de performances . Voici quelques situations courantes dans lesquelles le rendu du navigateur est redistribué :

  1. Modification de la taille de la fenêtre : Lorsque la taille de la fenêtre change, la mise en page change et la disposition des éléments doit être recalculée et redessinée.
window.addEventListener('resize', function () {
    
    
  // 窗口大小改变的操作
});
  1. Modification de la taille d'un élément : lors de la modification de la largeur, de la hauteur, des marges intérieures et extérieures et d'autres attributs d'un élément, le navigateur recalculera la disposition de l'élément.
element.style.width = "200px";
element.style.height = "100px";
  1. Modification de la position d'un élément : lors de la modification de l'attribut de position d'un élément (haut, gauche, droite, bas), cela entraînera la disposition de ses éléments environnants.
element.style.position = "absolute";
element.style.left = "100px";
element.style.top = "50px";
  1. Ajout ou suppression d'éléments : Lors de l'ajout ou de la suppression d'éléments, la mise en page de la page entière changera et tous les éléments devront recalculer la mise en page.
document.body.appendChild(newElement);
document.body.removeChild(elementToRemove);
  1. Modification du contenu d'un élément : Lorsque le contenu texte ou la structure HTML d'un élément est modifié, cela provoque une nouvelle présentation de l'élément et de ses éléments environnants.
element.textContent = "New Content";
element.innerHTML = "<p>New HTML</p>";
  1. Calculer certaines propriétés : Lors de l'obtention de certaines propriétés calculées (telles que offsetWidth, offsetHeight, clientWidth, clientHeight, etc.), le navigateur doit recalculer la disposition de l'élément.
var width = element.offsetWidth;
var height = element.offsetHeight;

3. Comment optimiser le reflux

La redistribution est le processus par lequel le navigateur recalcule et redessine la mise en page de la page Web, ce qui est une opération très gourmande en performances. L'optimisation de la redistribution peut améliorer les performances de rendu des pages Web. Voici quelques méthodes couramment utilisées :

1. Utilisez la transformation et l'opacité au lieu de propriétés telles que haut, gauche et largeur pour réaliser des effets d'animation. Parce que la transformation et l'opacité ne provoqueront pas de refusion.

Supposons qu'il y ait un bouton et que vous souhaitiez afficher un effet d'animation lorsque vous cliquez dessus, vous pouvez utiliser transformet opacitypour y parvenir au lieu d'utiliser des attributs tels que top, leftet . widthVoici un exemple de cas réel :

Structure HTML :

<button id="myButton">点击我</button>

Styles CSS :

#myButton {
    
    
  position: relative;
  padding: 10px 20px;
  background-color: blue;
  color: white;
  transform: scale(1);
  opacity: 1;
  transition: transform 0.3s, opacity 0.3s;
}

#myButton.clicked {
    
    
  transform: scale(0.8);
  opacity: 0;
}

Code Javascript :

var button = document.getElementById("myButton");
button.addEventListener("click", function() {
    
    
  button.classList.add("clicked");
});

Dans l'exemple ci-dessus, l'élément bouton a l'initiale transformet opacityles attributs par défaut. Lorsque vous cliquez sur le bouton, clickedun effet d'animation est déclenché par l'ajout d'une classe. Cette classe modifiera les boutons transformet opacityles propriétés pour obtenir des effets de mise à l'échelle et de fondu.

Étant donné transformque opacityles modifications de propriétés ne provoquent pas de redistribution, cette méthode d'animation peut offrir une expérience utilisateur plus fluide, en particulier lorsqu'il s'agit d'effets d'animation complexes.

2. Essayez d'utiliser le positionnement absolu (position : absolue) pour déplacer les éléments au lieu de modifier les propriétés de disposition des éléments. Étant donné que le positionnement absolu s'éloigne du flux de documents, il n'entraînera pas de nouvelle disposition des autres éléments.

Utilisez le positionnement absolu ( position: absolute) pour déplacer des éléments hors du flux normal de documents et les positionner avec précision, en évitant la redistribution.

Voici un exemple de cas réel :

Le code HTML est le suivant :

<div class="container">
  <div class="box"></div>
</div>

Le style CSS est le suivant :

.container {
    
    
  position: relative;
  width: 300px;
  height: 200px;
  border: 1px solid #000;
}

.box {
    
    
  position: absolute;
  top: 50px;
  left: 50px;
  width: 100px;
  height: 100px;
  background-color: red;
}

Dans ce cas, .containerun conteneur parent positionné de manière relative .boxet un élément enfant positionné de manière absolue. En définissant la valeur et la valeur .boxdu , il peut être positionné avec précision à la position spécifiée du .topleft.container

De cette façon, lors du changement .boxde position de l'élément, cela n'entraînera pas .containerde modification de la taille du conteneur parent ou des propriétés de disposition des autres éléments, évitant ainsi l'apparition de redistribution.

Résumer:

  • Définissez la valeur du conteneur parent ( .container) pour créer un point de référence pour le positionnement relatif.positionrelative
  • Définissez la position d' un élément enfant ( .box) pour qu'il sorte du flux de documents normal.positionabsolute
  • Utilisez toples attributs et leftpour positionner précisément les éléments enfants.

De cette façon, en utilisant le positionnement absolu, les éléments peuvent être déplacés sans modifier leurs propriétés de mise en page, évitant ainsi la redistribution.

3. Évitez d'utiliser la disposition du tableau, car la modification du contenu de chaque cellule du tableau entraînera une redistribution. Un effet similaire peut être obtenu en utilisant CSS display: table et display: table-cell.

Une utilisation courante tabledes mises en page consiste à créer un menu de navigation centré horizontalement, dans lequel la largeur de chaque élément de menu est ajustée dynamiquement en fonction du contenu.

Le code utilisant tableune mise en page pourrait ressembler à ceci :

<table class="nav">
  <tr>
    <td>菜单项1</td>
    <td>菜单项2</td>
    <td>菜单项3</td>
    <td>菜单项4</td>
  </tr>
</table>

Cependant, cette méthode de mise en page entraînera une redistribution, car la largeur de chaque cellule doit être ajustée dynamiquement en fonction du contenu.

Une tablefaçon d'éviter d'utiliser la mise en page consiste à utiliser les CSS display: tableet display: table-cellles propriétés pour obtenir un effet similaire tout en évitant la redistribution. Le code ressemble à ceci :

<div class="nav">
  <div class="nav-item">菜单项1</div>
  <div class="nav-item">菜单项2</div>
  <div class="nav-item">菜单项3</div>
  <div class="nav-item">菜单项4</div>
</div>
.nav {
    
    
  display: table;
  width: 100%;
}

.nav-item {
    
    
  display: table-cell;
  text-align: center;
}

.nav-item:hover {
    
    
  background-color: gray;
}

Dans cet exemple, un <div>élément est utilisé comme conteneur du menu de navigation, configuré display: tablepour simuler l'effet de la disposition du tableau, et chaque élément de menu est utilisé display: table-cellpour simuler les cellules du tableau.

L’avantage est que la largeur de chaque élément de menu s’adaptera au contenu sans provoquer de redistribution. De plus, CSS peut être utilisé pour ajouter des styles aux éléments de menu, comme changer la couleur d'arrière-plan lorsque la souris est survolée.

En conclusion, en simulant la disposition du tableau à l'aide des attributs display: tableet display: table-cell, la redistribution peut être évitée et la disposition et le style peuvent être contrôlés de manière plus flexible.

4. Pour éviter de modifier le style de l'élément DOM plusieurs fois dans la boucle, vous pouvez d'abord enregistrer le style à modifier dans une variable, puis mettre à jour le style de l'élément DOM en une seule fois.

Prenons comme exemple la modification du style de tous les éléments d'une liste, supposons qu'il y ait un élément <ul> et que vous souhaitiez définir la couleur d'arrière-plan de tous les éléments <li> sur rouge. Si le style de l'élément DOM est modifié plusieurs fois dans la boucle, cela entraînera plusieurs redistributions et affectera les performances.

Voici un moyen d'éviter la redistribution, enregistrez d'abord le style qui doit être modifié dans un objet, puis mettez à jour le style de l'élément DOM immédiatement :

// 获取<ul>元素
const list = document.querySelector('ul');

// 创建一个对象,存储需要修改的样式
const styles = {
    
    
  backgroundColor: 'red'
};

// 循环遍历所有的<li>元素
const items = list.getElementsByTagName('li');
for(let i = 0; i < items.length; i++) {
    
    
  // 将需要修改的样式应用到每个<li>元素
  Object.assign(items[i].style, styles);
}

Comme vous pouvez le voir dans le code ci-dessus, utilisez d'abord querySelector pour obtenir l'élément <ul> à utiliser, puis créez un objet styles, qui stocke le style qui doit être modifié. Ici, seule la couleur d'arrière-plan est définie sur rouge. . Ensuite, utilisez getElementsByTagName pour obtenir tous les éléments <li>, appliquez le style stocké à chaque élément <li> via un parcours de boucle et attribuez l'attribut de style sur l'objet styles à l'élément li en même temps via le style de la méthode Object.assign. attribut.

De cette manière, l'effet de définition de la couleur d'arrière-plan de tous les éléments <li> sur rouge est obtenu, ce qui évite de modifier le style des éléments DOM plusieurs fois dans la boucle, réduit le nombre de redistributions et améliore les performances.

5. Pour éviter de lire fréquemment les propriétés de mise en page (telles que offsetWidth, offsetHeightetc.), vous pouvez mettre en cache les valeurs de ces propriétés pour les utiliser.

Dans le développement réel, la lecture fréquente des attributs de mise en page (tels que offsetWidth, offsetHeightetc.) entraînera une redistribution fréquente du navigateur (redistribution), affectant les performances de la page. Pour éviter cette situation, les valeurs de ces propriétés peuvent être mises en cache pour être utilisées.

Un cas d’utilisation pratique consiste à obtenir la hauteur d’un élément lors du défilement. Dans certains scénarios, nous devons obtenir la hauteur de l'élément à traiter, mais si nous appelons directement pour obtenir la hauteur dans chaque événement de défilement offsetHeight, cela provoquera des redistributions fréquentes.

Afin d'éviter cette situation, nous pouvons mettre en cache la hauteur de l'élément après le chargement de la page ou le rendu de l'élément, au lieu de le lire à chaque événement de défilement.

L'exemple de code est le suivant :

// 获取元素
const element = document.getElementById('scrollElement');

// 缓存元素的高度
let cachedHeight = element.offsetHeight;

// 监听滚动事件
window.addEventListener('scroll', () => {
    
    
  // 使用缓存的高度进行处理
  // ...
});

Dans le code ci-dessus, nous mettons en cache la hauteur de l'élément dans cachedHeightune variable après le chargement de la page ou le rendu de l'élément. Ensuite, lorsque l'événement scroll se déclenche, nous utilisons directement la hauteur mise en cache pour le traitement au lieu d'appeler offsetHeightget height à chaque fois.

Cela peut éviter une lecture fréquente des propriétés de mise en page, réduire le nombre de redistributions et améliorer les performances des pages. Il convient de noter que dans certains cas particuliers, comme lorsque la hauteur d'un élément change de manière dynamique, la hauteur du cache doit être mise à jour dans le temps.

6. Utilisez la technologie DOM virtuelle, telle que des frameworks tels que React et Vue.js, pour mettre à jour uniquement la partie modifiée lorsque le composant est mis à jour, plutôt que l'intégralité de l'arborescence DOM.

Les frameworks qui utilisent la technologie DOM virtuel, tels que React et Vue.js, peuvent éviter les redistributions en mettant à jour des parties de l'arborescence DOM réelle en comparant les modifications apportées à l'arborescence DOM virtuelle.

Pour donner un cas pratique à illustrer, supposons que nous ayons une liste d’utilisateurs contenant plusieurs composants d’informations utilisateur. Nous souhaitons implémenter une fonction de recherche d'utilisateur simple. Une fois que l'utilisateur a saisi un mot-clé, la liste doit afficher les informations utilisateur correspondantes.

Tout d'abord, dans React, nous pouvons définir un composant UserList pour afficher une liste d'utilisateurs :

class UserList extends React.Component {
    
    
  render() {
    
    
    return (
      <div>
        {
    
    this.props.users.map(user => (
          <UserItem key={
    
    user.id} user={
    
    user} />
        ))}
      </div>
    );
  }
}

De même dans Vue.js :

Vue.component('user-list', {
    
    
  props: ['users'],
  template: `
    <div>
      <user-item v-for="user in users" :key="user.id" :user="user" />
    </div>
  `,
});

Le composant UserItem est un composant utilisé pour afficher des informations sur un seul utilisateur. Nous pouvons ajouter une zone de saisie à ce composant pour saisir des mots-clés de recherche :

class UserItem extends React.Component {
    
    
  constructor(props) {
    
    
    super(props);
    this.state = {
    
    
      search: '',
    };
  }

  handleSearchChange = (event) => {
    
    
    this.setState({
    
     search: event.target.value });
  }

  render() {
    
    
    const {
    
     user } = this.props;
    const {
    
     search } = this.state;

    return (
      <div>
        <h3>{
    
    user.name}</h3>
        <p>{
    
    user.email}</p>
        <input type="text" value={
    
    search} onChange={
    
    this.handleSearchChange} />
      </div>
    );
  }
}

Dans Vue.js, nous pouvons également implémenter une logique similaire :

Vue.component('user-item', {
    
    
  props: ['user'],
  data() {
    
    
    return {
    
    
      search: '',
    };
  },
  methods: {
    
    
    handleSearchChange(event) {
    
    
      this.search = event.target.value;
    },
  },
  template: `
    <div>
      <h3>{
     
     { user.name }}</h3>
      <p>{
     
     { user.email }}</p>
      <input type="text" v-model="search" />
    </div>
  `,
});

Désormais, chaque fois que l'utilisateur saisit un mot-clé dans une zone de saisie, l'état de recherche du composant correspondant sera mis à jour. Étant donné que React et Vue.js utilisent la technologie DOM virtuel, ils compareront la différence entre les deux arborescences DOM virtuelles avant et après, et mettront à jour uniquement la partie modifiée vers l'arborescence DOM réelle.

Ici, il suffit d'afficher dynamiquement les informations utilisateur dans le composant UserItem en fonction des mots-clés de recherche. Par exemple, dans React :

class UserItem extends React.Component {
    
    
  // ...

  render() {
    
    
    const {
    
     user } = this.props;
    const {
    
     search } = this.state;

    if (search && !user.name.toLowerCase().includes(search.toLowerCase())) {
    
    
      // 不匹配搜索关键字时,返回null,不渲染该用户信息
      return null;
    }

    return (
      <div>
        <h3>{
    
    user.name}</h3>
        <p>{
    
    user.email}</p>
        <input type="text" value={
    
    search} onChange={
    
    this.handleSearchChange} />
      </div>
    );
  }
}

Dans Vue.js, vous pouvez utiliser la directive v-if pour obtenir une logique similaire :

Vue.component('user-item', {
    
    
  // ...

  template: `
    <div v-if="!search || user.name.toLowerCase().includes(search.toLowerCase())">
      <h3>{
     
     { user.name }}</h3>
      <p>{
     
     { user.email }}</p>
      <input type="text" v-model="search" />
    </div>
  `,
});

De cette manière, chaque fois qu'un utilisateur entre dans une recherche par mot-clé, seule la partie des informations utilisateur correspondantes est mise à jour au lieu de l'intégralité de l'arborescence DOM. Cela évite les refusions inutiles et améliore les performances.

7. Utilisez la propriété will-change de CSS pour indiquer au navigateur à l'avance qu'un élément est sur le point d'être modifié, et le navigateur peut effectuer certaines optimisations sur l'élément.

Définir un attribut d'un élément will-changesur un attribut indique au navigateur que l'élément est sur le point d'être modifié et que le navigateur peut effectuer certaines optimisations sur l'élément pour éviter les redistributions. Cela améliore les performances et évite les calculs de mise en page inutiles.

Voici un will-changeexemple pratique d’utilisation des attributs :

HTML :

<div class="box">这是一个 Box</div>

CSS :

.box {
    
    
  width: 100px;
  height: 100px;
  background-color: red;
  transition: transform 1s ease-in-out;
}

.box:hover {
    
    
  transform: scale(1.2);
  will-change: transform;
}

Dans ce cas, lorsque la souris survole l’élément box, l’élément sera mis à l’échelle. Nous définissons l'attribut .box:hoverdans le sélecteur pour indiquer au navigateur que c'est l'attribut que l'élément est sur le point d'être modifié.will-changetransformtransform

De cette façon, le navigateur sait qu'il doit effectuer quelques optimisations avant que l'élément box ne soit mis à l'échelle pour éviter les redistributions inutiles. transformPar exemple, les navigateurs peuvent préparer les couches de rendu avant toute modification pour empêcher les recalculs de mise en page.

L'utilisation will-changede propriétés peut améliorer les performances, en particulier lorsqu'il s'agit d'éléments volumineux qui doivent être modifiés ou d'animations complexes. Cependant, une mauvaise utilisation des will-changeattributs peut entraîner des problèmes de performances, veillez donc à ne les appliquer qu'aux éléments et attributs nécessaires.

8. Pour éviter de modifier fréquemment la structure de l'arborescence DOM, certaines stratégies d'optimisation peuvent être adoptées, telles que l'utilisation d'un fragment de document (DocumentFragment) pour les opérations d'insertion et de suppression par lots, ou l'utilisation de l'épissage de chaînes pour générer du code HTML.

documentFragment
Dans un cas pratique, supposons qu'il existe une liste de tâches dans laquelle les utilisateurs peuvent ajouter, supprimer et effectuer des tâches. Chaque fois que l'utilisateur effectue ces opérations, la structure de l'arborescence DOM sera modifiée, ce qui peut entraîner des redistributions et des redessins fréquents, réduisant ainsi les performances et l'expérience utilisateur.

Afin d'éviter de modifier fréquemment la structure de l'arborescence DOM, nous pouvons utiliser des fragments de documents pour les opérations d'insertion et de suppression par lots. Un fragment de document est un conteneur de nœuds DOM léger qui peut contenir un ensemble de nœuds, mais ne crée pas de nœuds réels dans le document.

Ce qui suit est un cas réel d'insertion par lots utilisant des fragments de document :

// 创建一个文档片段
var fragment = document.createDocumentFragment();

// 获取待办事项列表的容器元素
var container = document.getElementById('todoList');

// 待添加的任务数据
var tasks = ['任务1', '任务2', '任务3'];

// 循环遍历任务列表
tasks.forEach(function(task) {
    
    
  // 创建新的任务元素
  var item = document.createElement('li');
  item.textContent = task;
  
  // 将任务元素添加到文档片段中
  fragment.appendChild(item);
});

// 将文档片段一次性插入到容器中
container.appendChild(fragment);

Dans ce cas, nous créons d'abord un fragment de document fragment, puis parcourons la liste des tâches, créons de nouveaux éléments de tâche et les ajoutons au fragment de document. Enfin, en insérant des fragments de document dans le conteneur en une seule fois, les modifications fréquentes de la structure arborescente du DOM sont évitées et le nombre de redistributions est réduit.

De même, nous pouvons utiliser des fragments de documents pour des opérations de suppression groupée. Ce qui suit est un cas réel de suppression groupée à l’aide de fragments de documents :

// 创建一个文档片段
var fragment = document.createDocumentFragment();

// 获取待删除的任务元素列表
var deleteList = document.querySelectorAll('.delete');

// 遍历待删除的任务元素列表
Array.prototype.forEach.call(deleteList, function(item) {
    
    
  // 将任务元素从文档中移除并添加到文档片段中
  fragment.appendChild(item);
});

// 从容器中一次性删除文档片段中的任务元素
container.removeChild(fragment);

Dans ce cas, nous créons d'abord un fragment de document fragment, puis obtenons la liste des éléments de tâche à supprimer via querySelectorAll. Ensuite, nous parcourons la liste, en supprimant chaque élément de tâche du document et en l'ajoutant au fragment de document. Enfin, en supprimant simultanément des fragments de document du conteneur, les modifications fréquentes de la structure arborescente du DOM sont évitées et le nombre de redistributions est réduit.

En utilisant des fragments de documents pour les opérations d'insertion et de suppression par lots, nous pouvons optimiser les opérations DOM, réduire le nombre de redistributions et améliorer les performances et l'expérience utilisateur.

Concaténation de chaînes :
supposons que nous ayons une liste de tâches à effectuer, les utilisateurs peuvent ajouter de nouvelles tâches via la zone de saisie et cliquer sur le bouton pour enregistrer. Chaque fois qu'un utilisateur ajoute une nouvelle tâche, nous devons ajouter dynamiquement la nouvelle tâche à la liste des tâches dans l'arborescence DOM. Afin d'éviter les problèmes de performances causés par la modification fréquente de la structure de l'arborescence DOM, nous pouvons utiliser la concaténation de chaînes pour générer du code HTML et insérer le HTML généré dans l'arborescence DOM en une seule fois.

<!DOCTYPE html>
<html>
<head>
  <title>待完成任务列表</title>
</head>
<body>
  <div id="taskList"></div>
  <input type="text" id="taskInput">
  <button id="addButton">Add Task</button>

  <script>
    var taskList = document.getElementById('taskList');
    var taskInput = document.getElementById('taskInput');
    var addButton = document.getElementById('addButton');
    var tasks = [];

    // 监听按钮点击事件
    addButton.addEventListener('click', function() {
      
      
      var taskName = taskInput.value;
      if (taskName) {
      
      
        tasks.push(taskName);

        // 使用字符串拼接生成HTML代码
        var html = '';
        for (var i = 0; i < tasks.length; i++) {
      
      
          html += '<div>' + tasks[i] + '</div>';
        }

        // 批量插入任务列表
        var fragment = document.createElement('div');
        fragment.innerHTML = html;
        taskList.appendChild(fragment);

        // 清空输入框
        taskInput.value = '';
      }
    });
  </script>
</body>
</html>

Dans le cas ci-dessus, lorsque l'utilisateur clique sur le bouton Ajouter, nous générons du code HTML en utilisant la concaténation de chaînes et insérons le code HTML généré dans la liste des tâches de l'arborescence DOM en une seule fois. Grâce à une insertion unique, les modifications fréquentes de la structure arborescente du DOM peuvent être évitées, réduisant ainsi le nombre de redistributions et améliorant les performances des pages.

9. Utilisez l'anti-rebond ou l'accélérateur pour réduire le nombre d'appels de redistribution fréquents, par exemple, utilisez les méthodes anti-rebond et throttle dans la bibliothèque lodash.

L'anti-shake ( debounce) et la limitation ( throttle) sont des méthodes d'optimisation couramment utilisées dans le développement front-end, qui sont utilisées pour limiter les temps d'exécution de certains événements fréquemment déclenchés et améliorer les performances des pages Web et l'expérience utilisateur.

Anti-shake : Après le déclenchement d'un événement, dans le délai spécifié, si l'événement est à nouveau déclenché, le chronométrage sera relancé. Ce n'est que lorsque l'événement n'est pas déclenché à nouveau dans le délai spécifié que le gestionnaire d'événements sera exécuté. Il est généralement utilisé pour optimiser les événements fréquemment déclenchés par les utilisateurs, comme la recherche en temps réel dans la zone de saisie. L'anti-shake peut empêcher l'envoi de requêtes fréquentes lorsque l'utilisateur tape continuellement, mais attendre que l'utilisateur arrête de taper avant de faire la requête, réduisant ainsi le nombre de requêtes et la pression du serveur.

Limitation : Après le déclenchement d'un événement, dans le délai spécifié, quel que soit le nombre de fois où l'événement est déclenché, la fonction de traitement d'événement ne sera exécutée qu'une seule fois. Généralement utilisé pour limiter certains événements à haute fréquence, tels que les événements de défilement de page. La limitation peut limiter la fréquence d'exécution des fonctions de traitement d'événements, éviter les problèmes de performances causés par des déclenchements fréquents et garantir la fluidité de la réponse des pages.

La différence entre les deux réside dans le moment de l'exécution . L'anti-shake consiste à attendre un certain temps après le déclenchement de l'événement avant d'exécuter la fonction de traitement d'événement, tandis que la limitation consiste à exécuter la fonction de traitement d'événement immédiatement après le déclenchement de l'événement et à ne l'exécuter qu'une seule fois dans le délai spécifié . L'anti-shake convient aux événements déclenchés fréquemment par les utilisateurs, tandis que la limitation convient aux événements déclenchés à haute fréquence.

Voici l'exemple de code pour implémenter la fonction anti-tremblement et la fonction de limitation en JavaScript :

Mise en œuvre de la fonction anti-tremblement :

function debounce(func, delay) {
    
    
    let timerId;
  
    return function() {
    
    
        clearTimeout(timerId);
        timerId = setTimeout(func, delay);
    }
}

// 使用示例
function handleDebounce() {
    
    
    console.log('Debounced function is called');
}

const debouncedFunc = debounce(handleDebounce, 300);
debouncedFunc(); // 只有在 300ms 内没有再次调用时才会执行 handleDebounce 函数

Implémentation de la fonction de limitation :

function throttle(func, delay) {
    
    
    let timerId;
    let lastExecTime = 0;
  
    return function() {
    
    
        const currentTime = Date.now();
        const elapsed = currentTime - lastExecTime;
        const context = this;
        const args = arguments;
        
        if (elapsed < delay) {
    
    
            clearTimeout(timerId);
            timerId = setTimeout(function() {
    
    
                lastExecTime = currentTime;
                func.apply(context, args);
            }, delay - elapsed);
        } else {
    
    
            lastExecTime = currentTime;
            func.apply(context, args);
        }
    }
}

// 使用示例
function handleThrottle() {
    
    
    console.log('Throttled function is called');
}

const throttledFunc = throttle(handleThrottle, 300);
throttledFunc(); // 间隔小于 300ms 时不执行 handleThrottle 函数,超过 300ms 才执行

Le rebond et l'accélération sont deux méthodes utilisées pour limiter la fréquence d'exécution des fonctions, ce qui peut nous aider à éviter le problème de redistribution causé par des appels fréquents. Ce qui suit est un cas pratique pour illustrer comment utiliser l'anti-rebond et l'accélérateur pour réduire le nombre de reflux.

Supposons que nous ayons un champ de recherche, lorsque l'utilisateur tape dans le champ de recherche, nous souhaitons effectuer l'opération de recherche dans les 500 millisecondes après que l'utilisateur arrête de taper afin de réduire les requêtes réseau inutiles.

Tout d’abord, nous devons importer la bibliothèque lodash, qui fournit des méthodes anti-rebond et d’accélération.

import {
    
     debounce, throttle } from 'lodash';

Ensuite, nous devons créer une fonction de recherche.

function search(query) {
    
    
  // 发起搜索请求的逻辑
  console.log('搜索关键词:', query);
}

Ensuite, nous pouvons utiliser la méthode anti-rebond pour créer une nouvelle fonction qui exécute la fonction de recherche 500 millisecondes après que l'utilisateur arrête de taper.

const debouncedSearch = debounce(search, 500);

Enfin, nous devons écouter les événements d’entrée de l’utilisateur et appeler la fonction deboundSearch.

const inputElement = document.querySelector('input');

inputElement.addEventListener('input', (event) => {
    
    
  const query = event.target.value;
  debouncedSearch(query);
});

De cette façon, lorsque l'utilisateur tape, la fonction anti-rebond Search ne sera appelée qu'une fois toutes les 500 millisecondes. Si l'utilisateur continue de taper dans les 500 millisecondes, la fonction anti-rebond Search ne sera pas appelée, évitant ainsi les requêtes réseau fréquentes.

De même, nous pouvons également utiliser la méthode throttle pour limiter la fréquence d'exécution de la fonction. La différence entre la méthode throttle et la méthode anti-rebond est que la throttle exécutera la fonction plusieurs fois dans un certain intervalle de temps, tandis que l'anti-rebond ne prendra effet que lors du dernier appel dans le délai spécifié. Selon la situation, choisir la bonne méthode peut nous aider à réduire le nombre de reflux.

10. L'utilisation de requestAnimationFrame au lieu de setInterval peut améliorer les performances du navigateur.

Utilisez requestAnimationFrame au lieu de setInterval pour créer une animation uniforme.
L'article ci-dessus enregistre un cas pratique d' utilisation requestAnimationFramedu remplacement . Si vous êtes intéressé, vous pouvez y jeter un œil.setInterval

Lorsqu'il est utilisé setIntervalpour créer des animations, il y aura un intervalle de temps fixe pour exécuter le code, mais cet intervalle de temps est inexact car il JavaScriptest monothread et l'exécution du code peut être affectée par d'autres tâches et événements. Cela rendra la fréquence d’images de l’animation instable, voire saccadée.

Quant à requestAnimationFramela méthode d'utilisation, le navigateur déterminera le timing d'exécution de la fonction de rappel en fonction de son propre taux de rafraîchissement, afin de garantir que la fréquence d'images de l'animation est stable et fluide. Dans le même temps, requestAnimationFramela méthode sera exécutée avant le redessin du navigateur, ce qui permettra de mieux synchroniser l'animation avec le processus de dessin du navigateur et d'éviter un redessin inutile.

De plus, requestAnimationFramela méthode peut également s'arrêter automatiquement lorsque l'animation est invisible, économisant ainsi des ressources informatiques inutiles.

En résumé, l'utilisation requestAnimationFramede remplacements setIntervalpeut améliorer les performances du navigateur et permettre des animations plus fluides et plus efficaces.

11. Minimisez le nombre et la complexité des éléments sur la page et masquez ou retardez le chargement des éléments qui n'ont pas besoin d'être affichés pour réduire l'apparition de redistribution.

En suivant la stratégie d'optimisation ci-dessus, le phénomène de reflux peut être efficacement réduit ou optimisé, et les performances de l'application Web développée frontale peuvent être améliorées.

Résumer

Dans cet article de blog, nous examinons l'optimisation du rendu du navigateur dans le cadre de l'optimisation des performances frontales. Nous avons appris que l'optimisation du processus de rendu du navigateur est essentielle lors de la création d'applications frontales hautes performances. En comprenant le processus de rendu du navigateur et en adoptant des stratégies d'optimisation efficaces, nous pouvons améliorer considérablement les performances des applications et l'expérience utilisateur.

Nous avons détaillé comment minimiser la hiérarchie de rendu et réduire les opérations de redistribution. En utilisant une structure HTML et CSS appropriée et en évitant les opérations DOM fréquentes, nous pouvons réduire le nombre de fois où le navigateur recalcule la mise en page et repeint, améliorant ainsi l'efficacité du rendu.

Dans l’ensemble, l’optimisation des performances de rendu du navigateur est l’une des clés pour améliorer les performances des applications frontales. En comprenant le processus de rendu du navigateur et en adoptant des stratégies d'optimisation efficaces, nous pouvons rendre nos applications plus efficaces et plus réactives, améliorant ainsi la satisfaction et l'expérience des utilisateurs.

Je suppose que tu aimes

Origine blog.csdn.net/jieyucx/article/details/132469062
conseillé
Classement