Optimización de la representación del navegador para optimizar el rendimiento del front-end

Directorio de artículos

introducción

En la era actual de rápido desarrollo de Internet, los usuarios tienen requisitos cada vez mayores en cuanto a velocidad de carga y rendimiento de las páginas web. Como desarrolladores front-end, debemos prestar atención y trabajar para mejorar el rendimiento de carga y representación de las páginas web para brindar una mejor experiencia de usuario. La optimización de la representación del navegador es la clave para lograr este objetivo. En este artículo, analizaremos algunos consejos y estrategias sobre la optimización de la representación del navegador, con el objetivo de ayudarlo a optimizar el proceso de representación de las páginas web y mejorar la velocidad de carga y el rendimiento de la página. Ya sea que esté comenzando como desarrollador front-end o un desarrollador experimentado, este artículo le brindará algunos consejos valiosos y prácticos para hacer que sus páginas web se muestren más rápido en el navegador. ¡Exploremos juntos cómo mejorar el rendimiento de la página web mediante la optimización de la representación del navegador!

1. Proceso de renderizado del navegador

El proceso de representación del navegador se refiere al proceso en el que el navegador analiza, diseña, dibuja y finalmente muestra recursos como HTML, CSS y JavaScript obtenidos del servidor al usuario . El siguiente es un diagrama de flujo simple de renderizado del navegador:

  1. Análisis de HTML : el navegador analiza HTMLel documento desde la parte superior y crea un DOMárbol (modelo de objetos de documento). DOMEl árbol representa HTMLla estructura del documento, incluidas etiquetas, atributos y nodos de texto.

  2. Análisis de CSS : el navegador analiza el CSSarchivo externo y aplica las reglas de estilo a DOMlos elementos correspondientes en el árbol. El proceso de análisis CSSproduce un árbol CSSOM( modelo de objetos), que es similar a un árbol pero representa información de estilo.CSSDOMCSS

  3. Construya un árbol de renderizado (árbol de renderizado) : el navegador fusiona DOMel árbol y CSSOMel árbol para construir un árbol de renderizado. El árbol de renderizado solo contiene elementos visibles que deben mostrarse en la página; por ejemplo, los elementos invisibles (p. ej. display:none) no se incluirán en el árbol de renderizado.

  4. Diseño : el navegador calcula el tamaño y la posición de cada elemento en el árbol de representación de la página y determina Box Modella información del modelo de cuadro (). Este proceso se llama diseño o reflujo ( reflow) y calcula la posición exacta de cada elemento en función de algunas CSSpropiedades (como etc.).width、height、position

  5. Dibujar (Pintar) : el navegador comienza a dibujar cada elemento en la pantalla en función de la información del árbol de renderizado y el diseño. El proceso de dibujo convierte cada elemento en una o más capas y utiliza GPUtécnicas de aceleración para mejorar el rendimiento.

  6. Rasterización : una vez completado el dibujo, el navegador divide la capa en pequeños mosaicos y los convierte en mapas de bits. Este proceso se llama rasterización y convierte los gráficos en píxeles que se pueden mostrar en la pantalla.

  7. Composición : el navegador compone todos los mosaicos en el orden correcto y genera el resultado final de la representación. Este proceso se llama composición y dibuja el mapa de bits en la pantalla, actualizando constantemente la representación en función de la interacción del usuario.

Todo el proceso se puede mostrar en forma de diagrama de flujo de la siguiente manera:

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

En resumen, el proceso de renderizado del navegador incluye pasos como análisis HTML, análisis CSS, construcción de un árbol de renderizado, diseño, dibujo, rasterización y composición. Estos pasos convierten HTML、CSSy JavaScriptconvierten páginas web en contenido web visible, lo que permite a los usuarios navegar por la web normalmente.

在这里补充一点
En el último paso del proceso de renderizado del navegador, Composición realiza principalmente el siguiente trabajo :

  1. Sintetizar el árbol de renderizado : el motor de composición combinará los elementos de la página en una o más capas de acuerdo con la estructura y la información de atributos de estilo del árbol de renderizado. Estas capas se pueden dibujar y componer de forma independiente según se desee.

  2. Dibujo de capas : en la etapa de composición, el motor de composición dibujará cada capa en un mapa de bits por separado. Este proceso suele tener lugar en la GPU, aprovechando las capacidades de aceleración del hardware para acelerar el dibujo.

  3. Composición de capas : El motor de composición sintetiza las capas dibujadas en el orden correcto. El proceso de composición realizará operaciones como la mezcla de transparencias y el enmascaramiento en mapas de bits de diferentes capas y, finalmente, generará un mapa de bits global para mostrar.

  4. Visualización y actualización de la lista de visualización : finalmente, el motor de composición envía el mapa de bits global generado a la pantalla a través del canal de visualización para su visualización. Al mismo tiempo, el motor de composición actualiza la lista de visualización de la página para reflejar la última representación.

En resumen, la composición ( Composition) es el último paso del proceso de renderizado del navegador, que incluye pasos como sintetizar el árbol de renderizado, dibujar y componer capas, generar el mapa de bits final y actualizar la lista de visualización, y finalmente muestra el resultado del renderizado en el usuario en la pantalla. Estos esfuerzos ayudan a mejorar el rendimiento de renderizado y la experiencia del usuario.

2. reflujo

1. ¿Qué es el reflujo?

El reflujo se refiere a que el navegador vuelve a representar parte o la totalidad del diseño de la página. Cuando la estructura, el estilo o las propiedades de diseño de la página cambian, el navegador activará el reflujo.

El reflujo se produce durante la fase de diseño de la representación del navegador. Hay dos pasos principales en el proceso de renderizado: diseño y pintura.

La etapa de diseño significa que el navegador calcula la posición y el tamaño de cada elemento en la página de acuerdo con el modelo de cuadro del elemento, establece la relación entre los elementos y genera un árbol de diseño (árbol de representación). Cuando el navegador descubre que la estructura o el estilo de la página ha cambiado durante la fase de diseño, activará un reflujo.

Durante el proceso de reflujo, el navegador atraviesa el árbol de diseño, calcula la posición y el tamaño de cada elemento y actualiza la información de representación correspondiente, luego regenera el árbol de diseño y el árbol de dibujo, y finalmente dibuja.

Cabe señalar que el reflujo es una operación que requiere relativamente mucho rendimiento, porque cuando se produce el reflujo, el navegador necesita recalcular el diseño de la página y actualizar la información de representación relacionada. Los reflujos frecuentes harán que el rendimiento de la página se degrade, por lo que la aparición de reflujos debe minimizarse durante el desarrollo para mejorar el rendimiento de la página.

2. ¿Qué operaciones pueden causar reflujo?

El reflujo de representación del navegador significa que cuando el diseño de la página y las propiedades geométricas cambian, el navegador recalculará el diseño de los elementos y los volverá a dibujar, lo que consume mucho rendimiento . A continuación se muestran algunas situaciones comunes en las que se redistribuye el procesamiento del navegador:

  1. Cambiar el tamaño de la ventana : cuando cambia el tamaño de la ventana, el diseño de la página cambiará y será necesario recalcular y volver a dibujar el diseño de los elementos.
window.addEventListener('resize', function () {
    
    
  // 窗口大小改变的操作
});
  1. Cambiar el tamaño del elemento : al cambiar el ancho, el alto, los márgenes interior y exterior y otros atributos de un elemento, el navegador volverá a calcular el diseño del elemento.
element.style.width = "200px";
element.style.height = "100px";
  1. Cambiar la posición del elemento : al cambiar los atributos de posición de un elemento (arriba, izquierda, derecha, abajo), provocará el diseño de los elementos circundantes.
element.style.position = "absolute";
element.style.left = "100px";
element.style.top = "50px";
  1. Agregar o eliminar elementos : al agregar o eliminar elementos, el diseño de toda la página cambiará y todos los elementos deberán volver a calcular el diseño.
document.body.appendChild(newElement);
document.body.removeChild(elementToRemove);
  1. Modificar el contenido de un elemento : cuando se modifica el contenido del texto o la estructura HTML de un elemento, se produce un rediseño del elemento y los elementos circundantes.
element.textContent = "New Content";
element.innerHTML = "<p>New HTML</p>";
  1. Calcule algunas propiedades : al obtener algunas propiedades calculadas (como offsetWidth, offsetHeight, clientWidth, clientHeight, etc.), el navegador debe volver a calcular el diseño del elemento.
var width = element.offsetWidth;
var height = element.offsetHeight;

3. Cómo optimizar el reflujo

Reflujo es el proceso mediante el cual el navegador recalcula y vuelve a dibujar el diseño de la página web, lo cual es una operación que consume mucho rendimiento. La optimización del reflujo puede mejorar el rendimiento de representación de las páginas web. A continuación se muestran algunos métodos utilizados habitualmente:

1. Utilice transformación y opacidad en lugar de propiedades como arriba, izquierda y ancho para realizar efectos de animación. Porque la transformación y la opacidad no provocarán reflujo.

Supongamos que hay un botón y desea mostrar un efecto de animación cuando hace clic en él, puede usar transformy opacitypara lograrlo en lugar de usar y otros atributos. A continuación se muestra un ejemplo de un caso real:topleftwidth

Estructura HTML:

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

Estilos 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;
}

Código JavaScript:

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

En el ejemplo anterior, el elemento del botón tiene los atributos inicial transformy opacityde forma predeterminada. Cuando se hace clic en el botón, clickedse activa un efecto de animación al agregar una clase. Esta clase cambiará las propiedades transformy los botones opacitypara lograr efectos de escala y desvanecimiento.

Dado que los cambios de propiedad transformy opacityno provocan reflujo, este método de animación puede proporcionar una experiencia de usuario más fluida, especialmente cuando se trata de efectos de animación complejos.

2. Intente utilizar el posicionamiento absoluto (posición: absoluta) para mover elementos en lugar de modificar las propiedades de diseño de los elementos. Debido a que el posicionamiento absoluto se separa del flujo de documentos, no provocará que otros elementos se vuelvan a diseñar.

Utilice el posicionamiento absoluto ( position: absolute) para sacar elementos del flujo normal de documentos y posicionarlos con precisión, evitando el reflujo.

A continuación se muestra un ejemplo de un caso real:

El código HTML es el siguiente:

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

El estilo CSS es el siguiente:

.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;
}

En este caso, .containerun contenedor principal en posición relativa .boxy un elemento hijo en posición absoluta. Al establecer el valor y el valor .boxde , se puede colocar con precisión en la posición especificada de .topleft.container

De esta manera, al cambiar .boxla posición del elemento, no cambiará .containerel tamaño del contenedor principal ni las propiedades de diseño de otros elementos, evitando así la aparición de reflujo.

Resumir:

  • Establezca el valor del contenedor principal ( .container) para crear un punto de referencia para el posicionamiento relativo.positionrelative
  • Establezca el valor de un elemento secundario ( .box) para sacar su posición del flujo normal de documentos.positionabsolute
  • Utilice toplos leftatributos y para colocar con precisión los elementos secundarios.

De esta manera, al utilizar el posicionamiento absoluto, los elementos se pueden mover sin cambiar sus propiedades de diseño, evitando así el reflujo.

3. Evite el uso del diseño de tabla, porque el cambio de contenido de cada celda de la tabla provocará un reflujo. Se puede lograr un efecto similar usando CSS display: table y display: table-cell.

Un uso común tablede los diseños es crear un menú de navegación centrado horizontalmente, donde el ancho de cada elemento del menú se ajusta dinámicamente según el contenido.

El código que utiliza tableun diseño podría verse así:

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

Sin embargo, este método de diseño provocará un reflujo, porque el ancho de cada celda debe ajustarse dinámicamente según el contenido.

Una tableforma de evitar el uso del diseño es utilizar CSS display: tabley display: table-cellpropiedades para lograr un efecto similar evitando el reflujo. El código se ve así:

<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;
}

En este ejemplo, <div>se utiliza un elemento como contenedor del menú de navegación, que está configurado display: tablepara simular el efecto del diseño de la tabla, y cada elemento del menú se utiliza display: table-cellpara simular las celdas de la tabla.

La ventaja de esto es que el ancho de cada elemento del menú se adaptará al contenido sin provocar reflujo. Además, CSS se puede utilizar para agregar estilos a los elementos del menú, como cambiar el color de fondo cuando se pasa el mouse sobre.

En conclusión, al simular el diseño de la tabla utilizando los atributos display: tabley display: table-cell, se puede evitar el reflujo y el diseño y el estilo se pueden controlar de manera más flexible.

4. Para evitar modificar el estilo del elemento DOM varias veces en el bucle, primero puede guardar el estilo que desea modificar en una variable y luego actualizar el estilo del elemento DOM a la vez.

Tomemos como ejemplo la modificación del estilo de todos los elementos en una lista, supongamos que hay un elemento <ul> y desea establecer el color de fondo de todos los elementos <li> que contiene en rojo. Si el estilo del elemento DOM se modifica varias veces en el bucle, provocará múltiples reflujos y afectará el rendimiento.

La siguiente es una forma de evitar el reflujo: primero guarde el estilo que debe modificarse en un objeto y luego actualice el estilo del elemento DOM de inmediato:

// 获取<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);
}

Como puede ver en el código anterior, primero use querySelector para obtener el elemento <ul> que se va a operar y luego cree un objeto de estilos, que almacena el estilo que debe modificarse, aquí solo el color de fondo se establece en rojo. . A continuación, use getElementsByTagName para obtener todos los elementos <li> y aplique el estilo almacenado a cada elemento <li> a través del recorrido del bucle, y asigne el atributo de estilo en el objeto de estilos al elemento li al mismo tiempo mediante el estilo del método Object.assign. atributo.

De esta manera, se logra el efecto de establecer el color de fondo de todos los elementos <li> en rojo, lo que evita modificar el estilo de los elementos DOM varias veces en el bucle, reduce la cantidad de reflujos y mejora el rendimiento.

5. Para evitar leer con frecuencia propiedades de diseño (como offsetWidth, offsetHeightetc.), puede almacenar en caché los valores de estas propiedades para su uso.

En el desarrollo real, la lectura frecuente de atributos de diseño (como offsetWidth, offsetHeightetc.) hará que el navegador se refluya con frecuencia, lo que afectará el rendimiento de la página. Para evitar esta situación, los valores de estas propiedades se pueden almacenar en caché para su uso.

Un caso de uso práctico es obtener la altura de un elemento mientras se desplaza. En algunos escenarios, necesitamos obtener la altura del elemento para procesar, pero si llamamos directamente para obtener la altura en cada evento de desplazamiento offsetHeight, provocará reflujos frecuentes.

Para evitar esta situación, podemos almacenar en caché la altura del elemento después de cargar la página o representar el elemento, en lugar de leerlo en cada evento de desplazamiento.

El código de muestra es el siguiente:

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

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

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

En el código anterior, almacenamos en caché la altura del elemento en cachedHeightuna variable después de que se carga la página o se representa el elemento. Luego, cuando se activa el evento de desplazamiento, usamos directamente la altura almacenada en caché en lugar de llamar offsetHeighta get height cada vez.

Hacerlo puede evitar la lectura frecuente de las propiedades de diseño, reducir la cantidad de reflujos y mejorar el rendimiento de la página. Cabe señalar que en algunos casos especiales, como cuando la altura de un elemento cambia dinámicamente, la altura del caché debe actualizarse a tiempo.

6. Utilice tecnología DOM virtual, como marcos como React y Vue.js, para actualizar solo la parte modificada cuando se actualiza el componente, en lugar de todo el árbol DOM.

Los marcos que utilizan tecnología DOM virtual, como React y Vue.js, pueden evitar reflujos actualizando partes del árbol DOM real comparando los cambios con el árbol DOM virtual.

Para dar un caso práctico para ilustrar, supongamos que tenemos una lista de usuarios que contiene múltiples componentes de información del usuario. Queremos implementar una función de búsqueda de usuarios simple: después de que el usuario ingresa una palabra clave, la lista debe mostrar la información del usuario coincidente.

Primero, en React, podemos definir un componente UserList para representar una lista de usuarios:

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

De manera similar en Vue.js:

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

El componente UserItem es un componente que se utiliza para mostrar información sobre un solo usuario. Podemos agregar un cuadro de entrada a este componente para ingresar palabras clave de búsqueda:

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>
    );
  }
}

En Vue.js, también podemos implementar una lógica similar:

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>
  `,
});

Ahora, cada vez que el usuario ingresa una palabra clave en cualquier cuadro de entrada, se actualizará el estado de búsqueda del componente correspondiente. Dado que React y Vue.js usan tecnología DOM virtual, compararán la diferencia entre los dos árboles DOM virtuales antes y después, y solo actualizarán la parte modificada al árbol DOM real.

Aquí, solo necesitamos mostrar dinámicamente la información del usuario en el componente UserItem de acuerdo con las palabras clave de búsqueda. Por ejemplo, en reaccionar:

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>
    );
  }
}

En Vue.js, puedes usar la directiva v-if para lograr una lógica similar:

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 esta manera, cada vez que un usuario ingresa una búsqueda de palabras clave, solo se actualiza la parte de la información del usuario coincidente en lugar de todo el árbol DOM. Esto evita reflujos innecesarios y mejora el rendimiento.

7. Utilice la propiedad will-change de CSS para indicarle al navegador de antemano que un elemento está a punto de modificarse y que el navegador puede realizar algunas optimizaciones en el elemento.

Establecer un atributo de un elemento will-changeen un atributo le dice al navegador que el elemento está a punto de ser modificado y que el navegador puede realizar algunas optimizaciones en el elemento para evitar reflujos. Esto mejora el rendimiento y evita cálculos de diseño innecesarios.

A continuación se muestra un will-changeejemplo práctico del uso de atributos:

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;
}

En este caso, cuando el mouse pasa sobre el elemento del cuadro, el elemento se escalará. Configuramos el atributo .box:hoveren el selector para decirle al navegador que es el atributo que el elemento está a punto de modificar.will-changetransformtransform

De esta manera, el navegador sabe que debe realizar algunas optimizaciones antes de escalar el elemento del cuadro para evitar reflujos innecesarios. transformPor ejemplo, los navegadores pueden preparar capas de renderizado antes de modificarlas para evitar nuevos cálculos del diseño.

El uso will-changede propiedades puede mejorar el rendimiento, especialmente cuando se trata de elementos grandes que necesitan cambiar o animaciones complejas. Sin embargo, el mal uso de will-changelos atributos puede causar problemas de rendimiento, así que asegúrese de aplicarlos únicamente a los elementos y atributos necesarios.

8. Para evitar modificar con frecuencia la estructura del árbol DOM, se pueden adoptar algunas estrategias de optimización, como usar Document Fragment (DocumentFragment) para operaciones de inserción y eliminación por lotes, o usar empalme de cadenas para generar código HTML.

documentFragment
En un caso práctico, supongamos que hay una lista de tareas pendientes donde los usuarios pueden agregar, eliminar y completar tareas. Cada vez que el usuario realiza estas operaciones, la estructura del árbol DOM se modificará, lo que puede provocar reflujos y redibujos frecuentes, lo que reduce el rendimiento y la experiencia del usuario.

Para evitar modificar con frecuencia la estructura del árbol DOM, podemos utilizar fragmentos de documentos para operaciones de inserción y eliminación por lotes. Un fragmento de documento es un contenedor de nodos DOM liviano que puede contener un conjunto de nodos, pero no crea nodos reales en el documento.

El siguiente es un caso real de inserción por lotes utilizando fragmentos de documentos:

// 创建一个文档片段
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);

En este caso, primero creamos un fragmento de documento fragment, luego recorremos la lista de tareas, creamos nuevos elementos de tarea y los agregamos al fragmento de documento. Finalmente, al insertar fragmentos de documentos en el contenedor al mismo tiempo, se evita la modificación frecuente de la estructura del árbol DOM y se reduce el número de reflujos.

De manera similar, podemos usar fragmentos de documentos para operaciones de eliminación masiva. El siguiente es un caso real de eliminación masiva utilizando fragmentos de documentos:

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

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

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

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

En este caso, primero creamos un fragmento de documento fragmenty luego obtenemos la lista de elementos de la tarea que se eliminarán mediante querySelectorAll. A continuación, recorremos la lista, eliminando cada elemento de tarea del documento y agregándolo al fragmento del documento. Finalmente, al eliminar fragmentos de documentos del contenedor a la vez, se evita la modificación frecuente de la estructura del árbol DOM y se reduce el número de reflujos.

Al utilizar fragmentos de documentos para operaciones de inserción y eliminación por lotes, podemos optimizar las operaciones DOM, reducir la cantidad de reflujos y mejorar el rendimiento y la experiencia del usuario.

Concatenación de cadenas:
supongamos que tenemos una lista de tareas por completar, los usuarios pueden agregar nuevas tareas a través del cuadro de entrada y hacer clic en el botón para guardar. Cada vez que un usuario agrega una nueva tarea, debemos agregar dinámicamente la nueva tarea a la lista de tareas en el árbol DOM. Para evitar problemas de rendimiento causados ​​por la modificación frecuente de la estructura del árbol DOM, podemos usar la concatenación de cadenas para generar código HTML e insertar el HTML generado en el árbol DOM al mismo tiempo.

<!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>

En el caso anterior, cuando el usuario hace clic en el botón Agregar, generamos código HTML mediante concatenación de cadenas e insertamos el código HTML generado en la lista de tareas en el árbol DOM al mismo tiempo. Mediante la inserción única, se pueden evitar modificaciones frecuentes de la estructura del árbol DOM, reduciendo así la cantidad de reflujos y mejorando el rendimiento de la página.

9. Utilice antirrebote o aceleración para reducir la cantidad de llamadas frecuentes de reflujo; por ejemplo, utilice los métodos antirrebote y aceleración en la biblioteca lodash.

Anti-vibración ( debounce) y limitación ( throttle) son métodos de optimización comúnmente utilizados en el desarrollo front-end, que se utilizan para limitar los tiempos de ejecución de ciertos eventos desencadenados con frecuencia y mejorar el rendimiento de la página web y la experiencia del usuario.

Antivibración : después de que se activa un evento, dentro del tiempo especificado, si el evento se activa nuevamente, se reiniciará el tiempo. Solo cuando el evento no se active nuevamente dentro del tiempo especificado, se ejecutará el controlador de eventos. Por lo general, se utiliza para optimizar eventos activados con frecuencia por los usuarios, como la búsqueda en tiempo real en el cuadro de entrada. Anti-vibración puede evitar que se envíen solicitudes frecuentes cuando el usuario escribe continuamente, pero espere a que el usuario deje de escribir antes de realizar la solicitud, lo que reduce la cantidad de solicitudes y la presión del servidor.

Limitación : después de que se activa un evento, dentro del tiempo especificado, no importa cuántas veces se active el evento, la función de procesamiento de eventos solo se ejecutará una vez. Generalmente se usa para limitar algunos eventos de alta frecuencia, como eventos de desplazamiento de página. La limitación puede limitar la frecuencia de ejecución de las funciones de procesamiento de eventos, evitar problemas de rendimiento causados ​​por activaciones frecuentes y garantizar la fluidez de la respuesta de la página.

La diferencia entre los dos radica en el momento de la ejecución . Anti-vibración consiste en esperar un período de tiempo después de que se activa el evento antes de ejecutar la función de procesamiento de eventos, mientras que la limitación consiste en ejecutar la función de procesamiento de eventos inmediatamente después de que se activa el evento y solo ejecutarla una vez dentro del tiempo especificado . La función antivibración es adecuada para eventos desencadenados con frecuencia por los usuarios, mientras que la limitación es adecuada para eventos desencadenados por alta frecuencia.

El siguiente es el código de muestra para implementar la función antivibración y la función de limitación en JavaScript:

Implementación de la función antivibración:

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 函数

Implementación de la función de estrangulamiento:

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 才执行

El rebote y la aceleración son dos métodos que se utilizan para limitar la frecuencia de ejecución de funciones, lo que puede ayudarnos a evitar el problema de reflujo causado por llamadas frecuentes. El siguiente es un caso práctico para ilustrar cómo utilizar el antirrebote y la aceleración para reducir el número de reflujos.

Supongamos que tenemos un cuadro de búsqueda, cuando el usuario escribe en el cuadro de búsqueda, queremos realizar la operación de búsqueda dentro de los 500 milisegundos después de que el usuario deja de escribir para reducir solicitudes de red innecesarias.

Primero, necesitamos importar la biblioteca lodash, que proporciona métodos antirrebote y de aceleración.

import {
    
     debounce, throttle } from 'lodash';

Luego, necesitamos crear una función de búsqueda.

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

A continuación, podemos usar el método antirrebote para crear una nueva función que ejecute la función de búsqueda 500 milisegundos después de que el usuario deja de escribir.

const debouncedSearch = debounce(search, 500);

Finalmente, necesitamos escuchar los eventos de entrada del usuario y llamar a la función debouncedSearch.

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

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

De esta manera, cuando el usuario escribe, la función debouncedSearch solo se llamará una vez cada 500 milisegundos. Si el usuario sigue escribiendo dentro de los 500 milisegundos, no se llamará a la función debouncedSearch, lo que evitará solicitudes frecuentes de red.

De manera similar, también podemos usar el método de aceleración para limitar la frecuencia de ejecución de la función. La diferencia entre el método de aceleración y el método de rebote es que el acelerador ejecutará la función varias veces dentro de un cierto intervalo de tiempo, mientras que el rebote solo tendrá efecto en la última llamada dentro del tiempo especificado. Dependiendo de la situación, elegir el método correcto puede ayudarnos a reducir la cantidad de reflujos.

10. Usar requestAnimationFrame en lugar de setInterval puede mejorar el rendimiento del navegador.

Use requestAnimationFrame en lugar de setInterval para hacer una animación uniforme.
El artículo anterior registra un caso práctico de cómo usar requestAnimationFrameel reemplazo . Si está interesado, puede echar un vistazo.setInterval

Cuando se usa setIntervalpara hacer animaciones, habrá un intervalo de tiempo fijo para ejecutar el código, pero este intervalo de tiempo es inexacto porque es de JavaScriptun solo subproceso y la ejecución del código puede verse afectada por otras tareas y eventos. Esto hará que la velocidad de fotogramas de la animación sea inestable o incluso tartamudee.

En cuanto requestAnimationFrameal método de uso, el navegador determinará el tiempo de ejecución de la función de devolución de llamada de acuerdo con su propia frecuencia de actualización, para garantizar que la velocidad de fotogramas de la animación sea estable y fluida. Al mismo tiempo, requestAnimationFrameel método se ejecutará antes de que el navegador lo vuelva a dibujar, lo que puede sincronizar mejor la animación con el proceso de dibujo del navegador y evitar un nuevo dibujo innecesario.

Además, requestAnimationFrameel método también puede pausarse automáticamente cuando la animación es invisible, lo que ahorra recursos informáticos innecesarios.

En resumen, el uso requestAnimationFramede anulaciones setIntervalpuede mejorar el rendimiento del navegador y permitir animaciones más fluidas y eficientes.

11. Minimice la cantidad y la complejidad de los elementos de la página y oculte o retrase la carga de elementos que no necesitan mostrarse para reducir la aparición de reflujo.

Siguiendo la estrategia de optimización anterior, el fenómeno de reflujo se puede reducir u optimizar de manera efectiva y se puede mejorar el rendimiento de la aplicación web desarrollada front-end.

Resumir

En esta publicación de blog, profundizamos en la optimización de la representación del navegador en la optimización del rendimiento del front-end. Aprendimos que optimizar el proceso de renderizado del navegador es fundamental al crear aplicaciones front-end de alto rendimiento. Al comprender el proceso de representación del navegador y adoptar algunas estrategias de optimización efectivas, podemos mejorar significativamente el rendimiento de la aplicación y la experiencia del usuario.

Detallamos cómo minimizar la jerarquía de renderizado y reducir las operaciones de redibujo de reflujo. Al utilizar una estructura HTML y CSS adecuada y evitar operaciones DOM frecuentes, podemos reducir la cantidad de veces que el navegador recalcula el diseño y repinta, mejorando así la eficiencia de renderizado.

En general, optimizar el rendimiento de renderizado del navegador es una de las claves para mejorar el rendimiento de las aplicaciones front-end. Al comprender el proceso de representación del navegador y adoptar algunas estrategias de optimización efectivas, podemos hacer que nuestras aplicaciones sean más eficientes y receptivas, mejorando así la satisfacción y la experiencia del usuario.

Supongo que te gusta

Origin blog.csdn.net/jieyucx/article/details/132469062
Recomendado
Clasificación