Renderización de HTML e interactividad del cliente

La renderización de HTML con JavaScript es distinta de la renderización de HTML que envía el servidor, y eso puede afectar el rendimiento. Obtenga información sobre la diferencia en esta guía y sobre lo que puede hacer para preservar el rendimiento de la renderización de su sitio web, especialmente en lo que respecta a las interacciones.

El análisis y la renderización de HTML es algo que los navegadores hacen muy bien de forma predeterminada para los sitios web que usan la lógica de navegación integrada del navegador, a veces denominadas "cargas tradicionales de páginas" o "navegaciones difíciles". Estos sitios web a veces se denominan aplicaciones de varias páginas (MPA).

Sin embargo, los desarrolladores pueden trabajar con los valores predeterminados del navegador para satisfacer las necesidades de sus aplicaciones. Sin dudas, este es el caso de los sitios web que usan el patrón de aplicación de una sola página (SPA), que crea de forma dinámica grandes partes del HTML/DOM en el cliente con JavaScript. La renderización del cliente es el nombre de este patrón de diseño y puede tener efectos en la Interacción con la siguiente pintura (INP) de tu sitio web si el trabajo involucrado es excesivo.

Esta guía te ayudará a comparar la diferencia entre usar el código HTML que envía el servidor al navegador y crearlo en el cliente con JavaScript, y cómo este último puede generar una alta latencia de interacción en momentos cruciales.

Cómo el navegador procesa el código HTML que proporciona el servidor

El patrón de navegación utilizado en las cargas de páginas tradicionales implica recibir HTML del servidor en cada navegación. Si ingresas una URL en la barra de direcciones de tu navegador o haces clic en un vínculo de una MPA, ocurre la siguiente serie de eventos:

  1. El navegador envía una solicitud de navegación para la URL proporcionada.
  2. El servidor responde con HTML en fragmentos.

El último paso es clave. También es una de las optimizaciones de rendimiento más fundamentales en el intercambio entre el servidor y el navegador, y se conoce como transmisión. Si el servidor puede comenzar a enviar HTML tan pronto como sea posible y el navegador no espera a que llegue toda la respuesta, puede procesar el código HTML en fragmentos a medida que llega.

Captura de pantalla del análisis del HTML que envió el servidor, visualizada en el panel de rendimiento de Herramientas para desarrolladores de Chrome. A medida que el HTML se transmite, fragmentos se procesan en tareas más cortas y la renderización es incremental.
Análisis y renderización del código HTML que proporciona el servidor, como se muestra en el panel de rendimiento de las Herramientas para desarrolladores de Chrome. Las tareas involucradas en el análisis del HTML y su renderización se dividen en fragmentos.

Al igual que la mayoría de las cosas que suceden en el navegador, el análisis de HTML se produce dentro de las tareas. Cuando se transmite HTML del servidor al navegador, este optimiza el análisis de ese HTML haciéndolo un poco a la vez a medida que llegan fragmentos de esa transmisión en fragmentos. La consecuencia es que el navegador entrega el subproceso principal periódicamente después de procesar cada fragmento, lo que evita las tareas largas. Esto significa que pueden llevarse a cabo otras tareas mientras se analiza HTML, incluido el trabajo de renderización incremental necesario para presentar una página al usuario, así como el procesamiento de las interacciones del usuario que puedan ocurrir durante el período crucial de inicio de la página. Este enfoque genera una mejor puntuación de Interaction to Next Paint (INP) para la página.

¿La conclusión? Cuando transmites HTML desde el servidor, obtienes un análisis y renderización incrementales de HTML, además de rendimiento automático para el subproceso principal de forma gratuita. Esto no se obtiene con la renderización del cliente.

Cómo el navegador procesa el código HTML proporcionado por JavaScript

Si bien cada solicitud de navegación a una página requiere que el servidor proporcione cierta cantidad de HTML, algunos sitios web utilizan el patrón SPA. Este enfoque a menudo implica que el servidor proporciona una carga útil inicial mínima de HTML, pero luego el cliente completará el área de contenido principal de una página con HTML recopilado a partir de los datos recuperados del servidor. Las navegaciones posteriores, a veces denominadas "navegaciones suaves" en este caso, son controladas completamente por JavaScript para propagar la página con HTML nuevo.

La renderización del cliente también puede ocurrir en casos que no son de SPA, en casos más limitados en los que HTML se agrega dinámicamente al DOM a través de JavaScript.

Existen algunas maneras comunes de crear HTML o agregar información al DOM por medio de JavaScript:

  1. La propiedad innerHTML te permite configurar el contenido de un elemento existente mediante una cadena, que el navegador analizará en el DOM.
  2. El método document.createElement te permite crear nuevos elementos para agregarlos al DOM sin usar ningún análisis de HTML del navegador.
  3. El método document.write te permite escribir HTML en el documento (y el navegador lo analiza, tal como en el enfoque n° 1). Sin embargo, debido a diversas razones, no se recomienda el uso de document.write.
Captura de pantalla del análisis del código HTML procesado a través de JavaScript, visualizada en el panel de rendimiento de Herramientas para desarrolladores de Chrome. El trabajo se realiza en una sola tarea larga que bloquea el subproceso principal.
Análisis y renderización de HTML a través de JavaScript en el cliente, como se muestra en el panel de rendimiento de las Herramientas para desarrolladores de Chrome. Las tareas involucradas en su análisis y renderización no se fragmentan, lo que genera una tarea larga que bloquea el subproceso principal.

Las consecuencias de crear HTML/DOM a través de JavaScript del cliente pueden ser significativas:

  • A diferencia de HTML que transmite el servidor en respuesta a una solicitud de navegación, las tareas de JavaScript en el cliente no se fragmentan automáticamente, lo que puede generar tareas largas que bloquean el subproceso principal. Esto significa que el INP de tu página puede verse afectado negativamente si estás creando demasiado HTML/DOM a la vez en el cliente.
  • Si se crea HTML en el cliente durante el inicio, el escáner de precarga del navegador no descubrirá los recursos a los que se hace referencia en él. Sin duda, esto tendrá un efecto negativo en el Largest Contentful Paint (LCP) de una página. Si bien esto no es un problema de rendimiento durante el tiempo de ejecución (es un problema de retraso de red en la recuperación de recursos importantes), no quieres que el LCP de tu sitio web se vea afectado por eludir esta optimización fundamental del rendimiento del navegador.

Qué puedes hacer respecto al impacto en el rendimiento de la renderización del cliente

Si tu sitio web depende en gran medida del procesamiento del cliente y observas valores de INP deficientes en los datos de campo, es posible que te preguntes si la renderización del cliente tiene algo que ver con el problema. Por ejemplo, si tu sitio web es una SPA, los datos de tu campo pueden revelar interacciones responsables de un trabajo de renderización considerable.

Cualquiera sea la causa, aquí hay algunas causas potenciales que puedes explorar para ayudar a retomar la situación.

Proporcionar la mayor cantidad posible de HTML del servidor

Como se mencionó antes, el navegador controla el HTML del servidor de forma predeterminada con un alto rendimiento. Divide el análisis y la renderización de HTML de una manera que evita tareas largas y optimiza el tiempo total del subproceso principal. Esto genera un Tiempo de bloqueo total (TBT) más bajo, y la TBT está muy correlacionada con el INP.

Es posible que uses un framework de frontend para compilar tu sitio web. Si es así, asegúrate de que estás renderizando el código HTML del componente en el servidor. Esto limitará la cantidad de renderización inicial del cliente que requerirá tu sitio web, lo que debería dar como resultado una mejor experiencia.

  • En el caso de React, te recomendamos usar la API de Server DOM para renderizar HTML en el servidor. Sin embargo, ten en cuenta que el método tradicional de renderización del servidor usa un enfoque síncrono, que puede generar un tiempo hasta el primer byte (TTFB) más extenso, además de métricas posteriores como First Contentful Paint (FCP) y LCP. Cuando sea posible, asegúrate de usar las APIs de transmisión para Node.js o otros entornos de ejecución de JavaScript, de modo que el servidor pueda comenzar a transmitir HTML al navegador lo antes posible. Next.js, un framework basado en React, proporciona muchas prácticas recomendadas de forma predeterminada. Además de renderizar automáticamente HTML en el servidor, también puede generar HTML de forma estática para las páginas que no cambian en función del contexto del usuario (como la autenticación).
  • Vue también realiza de forma predeterminada la renderización del cliente. Sin embargo, al igual que en React, Vue también puede renderizar el HTML de tu componente en el servidor. Aprovecha estas APIs del servidor cuando sea posible o considera una abstracción de nivel superior en tu proyecto de Vue para facilitar la implementación de las prácticas recomendadas.
  • Svelte procesa HTML en el servidor de forma predeterminada. Sin embargo, si el código de tu componente necesita acceder a los espacios de nombres exclusivos del navegador (por ejemplo, window), es posible que no puedas renderizar el HTML de ese componente en el servidor. Explora enfoques alternativos siempre que sea posible para no causar una renderización innecesaria del cliente. SvelteKit, que es a Svelte como Next.js es a React, incorpora muchas prácticas recomendadas a tus proyectos de Svelte como sea posible, de modo que puedas evitar posibles dificultades en proyectos que solo usan Svelte.

Limita la cantidad de nodos del DOM que se crean en el cliente

Cuando los DOM son grandes, el tiempo de procesamiento necesario para renderizarlos suele aumentar. Ya sea que tu sitio web sea una SPA completa o que esté inyectando nodos nuevos en un DOM existente como resultado de la interacción con una MPA, considera mantener esos DOM lo más pequeños posible. Esto ayudará a reducir el trabajo requerido durante la renderización del cliente para mostrar ese HTML. Con suerte, ayudará a mantener el INP de tu sitio web más bajo.

Considera una arquitectura de service worker de transmisión

Esta es una técnica avanzada, que puede no funcionar fácilmente con todos los casos de uso, pero es una que puede convertir tu MPA en un sitio web que parezca que se carga al instante cuando los usuarios navegan de una página a la siguiente. Puedes usar un service worker para almacenar previamente en caché las partes estáticas de tu sitio web en CacheStorage y usar la API de ReadableStream para recuperar el resto del código HTML de una página del servidor.

Si usas esta técnica correctamente, no crearás HTML en el cliente, pero la carga instantánea de fragmentos de contenido desde la caché dará la impresión de que tu sitio se carga rápidamente. Los sitios web que usan este enfoque pueden parecer casi como un SPA, pero sin las desventajas de la renderización del lado del cliente. También reduce la cantidad de HTML que solicitas al servidor.

En resumen, una arquitectura de service worker de transmisión no reemplaza la lógica de navegación integrada del navegador, sino que la agrega. Si deseas obtener más información para lograr esto con Workbox, consulta Aplicaciones más rápidas de varias páginas con transmisiones.

Conclusión

La manera en que tu sitio web recibe y procesa HTML tiene un impacto en el rendimiento. Cuando dependes del servidor para que envíe todo (o la mayor parte) del código HTML necesario para que funcione tu sitio web, obtienes mucho contenido gratuito: análisis y renderización incrementales, y rendimiento automático para el subproceso principal a fin de evitar tareas largas.

El procesamiento de HTML del cliente presenta una serie de posibles problemas de rendimiento que se pueden evitar en muchos casos. Sin embargo, debido a los requisitos de cada sitio web individual, no se puede evitar del todo el 100% de las veces. Para mitigar las posibles tareas largas que pueden resultar de una representación excesiva en el sitio del cliente, asegúrate de enviar la mayor cantidad de código HTML de tu sitio web desde el servidor siempre que sea posible, procura que los tamaños de DOM sean lo más pequeños posible para el HTML que se debe procesar en el cliente, y considera arquitecturas alternativas para acelerar la entrega de HTML al cliente y, al mismo tiempo, aprovechar el análisis y la renderización incrementales que el navegador proporciona para el HTML que se carga desde el servidor.

Si logras que la renderización del cliente de tu sitio web sea lo más mínima posible, mejorarás no solo el INP de tu sitio web, sino otras métricas como LCP, TBT y, posiblemente, incluso tu TTFB en algunos casos.

Hero image de Unsplash, de Maik Jonietz.