Hoy traemos a su atención una traducción del segundo material de una serie dedicada a la optimización de instagram.com. Aquí hablaremos sobre cómo mejorar el mecanismo para la ejecución temprana de consultas GraphQL y aumentar la eficiencia de la transmisión de datos HTML al cliente.

→ Leer con la respiración contenida, la
primera parteEnvío de datos iniciado por el servidor al cliente utilizando tecnología de descarga HTML progresiva
En la primera parte, hablamos sobre cómo, utilizando mecanismos de precarga, comenzar a ejecutar consultas en las primeras etapas del procesamiento de la página. Es decir, incluso antes de que se cargue el script que inicia tales solicitudes. Dado esto, se puede observar que la ejecución de estas solicitudes en la etapa de precarga de materiales todavía significaba que su ejecución no comenzó antes de la presentación de la página HTML en el cliente. Y esto, a su vez, significaba que la solicitud no podía comenzar antes de que el cliente enviara una solicitud al servidor y este respondiera (aquí también debe agregar el tiempo que le toma al servidor generar una respuesta HTML al cliente). En la siguiente figura, puede ver que el inicio de una consulta GraphQL puede retrasarse bastante. Y esto es así, dado que comenzamos a realizar tales solicitudes utilizando el código ubicado en la etiqueta HTML
<head>
, y que esta es una de las primeras tareas que resolvemos con la ayuda de herramientas de precarga de datos.
La ejecución preliminar de la solicitud comienza con un retraso notable.En teoría, el inicio de una consulta GraphQL de este tipo sería ideal en el momento en que se envió una solicitud para cargar la página correspondiente al servidor. Pero, ¿cómo hacer que el navegador comience a descargar algo incluso antes de que reciba al menos un código HTML del servidor? La respuesta es enviar el recurso al navegador por iniciativa del servidor. Puede parecer que para implementar dicho mecanismo, necesitará algo como HTTP / 2 Server Push. Pero, de hecho, existe una tecnología muy antigua (que a menudo se olvida) que le permite implementar un esquema similar de interacción entre el cliente y el servidor. Esta tecnología se caracteriza por el soporte universal del navegador, para su implementación no es necesario profundizar en las complejidades de infraestructura que son típicas para implementar HTTP / 2 Server Push. Facebook ha estado utilizando esta tecnología desde 2010 (lea sobre
BigPipe ), y en otros sitios como Ebay, también encuentra aplicaciones en varias formas. Pero parece que los desarrolladores de JavaScript de aplicaciones de una sola página básicamente ignoran esta tecnología o simplemente no la usan. Se trata de cargar progresivamente HTML. Esta tecnología se conoce con varios nombres: "descarga temprana", "descarga de cabeza", "HTML progresivo". Funciona gracias a una combinación de dos mecanismos:
- El primero es la codificación de transferencia fragmentada HTTP.
- El segundo es la representación progresiva de HTML en el navegador.
El mecanismo de
codificación de transferencia fragmentada apareció en HTTP / 1.1. Le permite dividir las respuestas HTTP en muchas partes pequeñas que se transmiten al navegador en modo de transmisión. El navegador "sujeta" estas partes a medida que llegan, formando el código de respuesta completo a partir de ellas. Aunque este enfoque proporciona cambios significativos en la forma en que se forman las páginas en el servidor, la mayoría de los lenguajes y marcos tienen la capacidad de proporcionar respuestas similares, divididas en partes. Las interfaces web de Instagram usan Django, por lo que usamos el objeto
StreamingHttpResponse . La razón por la cual el uso de este mecanismo puede ser beneficioso es que le permite enviar el contenido HTML de la página al navegador en modo de transmisión, ya que las partes individuales de la página están listas, en lugar de esperar a que el código completo de la página esté listo. Esto significa que podemos borrar el título de la página del navegador casi instantáneamente después de recibir la solicitud (de ahí el término "descarga temprana"). La preparación del encabezado no requiere recursos de servidor particularmente grandes. Esto permite que el navegador comience a cargar scripts y estilos incluso cuando el servidor está ocupado generando datos dinámicos para el resto de la página. Veamos qué efecto tiene esta técnica. Así es como se ve una carga de página normal.
No se utiliza la tecnología de descarga temprana: la carga de recursos no comienza hasta que la página HTML esté completamente cargadaPero, ¿qué sucede si el servidor, al recibir la solicitud, pasa inmediatamente el título de la página al navegador?
Se utiliza la tecnología de descarga temprana: los recursos comienzan a cargarse inmediatamente después de que las etiquetas HTML se vuelcan en el navegadorAdemás, podemos usar el mecanismo de enviar mensajes HTTP en partes para enviar datos al cliente cuando estén listos. En el caso de las aplicaciones que se representan en el servidor, estos datos se pueden presentar en forma de código HTML. Pero si estamos hablando de aplicaciones de una sola página como instagram.com, el servidor también puede transmitir algo como datos JSON al cliente. Para ver cómo funciona esto, veamos el ejemplo más simple de iniciar una aplicación de una sola página.
Primero, el marcado HTML original se envía al navegador que contiene el código JavaScript necesario para representar la página. Después de analizar y ejecutar este script, se ejecutará una solicitud XHR, cargando los datos de origen necesarios para representar la página.
El proceso de cargar una página en una situación en la que el navegador solicita independientemente del servidor todo lo que necesitaEste proceso involucra varias situaciones en las que el cliente envía una solicitud al servidor y espera una respuesta del mismo. Como resultado, hay períodos en que tanto el servidor como el cliente están inactivos. En lugar de esperar a que el servidor espere la solicitud de API del cliente, sería más efectivo si el servidor comenzara a preparar una respuesta de API inmediatamente después de que se generó el código HTML. Una vez que la respuesta estuvo lista, el servidor podría, por iniciativa propia, envenenarla para el cliente. Esto significaría que para cuando el cliente haya preparado todo lo necesario para visualizar los datos que se cargaron previamente después de que se completó la solicitud de API, es probable que estos datos estén listos. El cliente no tendría que cumplir una solicitud por separado al servidor y esperar una respuesta de él.
El primer paso para implementar dicho esquema de interacción cliente-servidor es crear un caché JSON diseñado para almacenar las respuestas del servidor. Desarrollamos esta parte del sistema utilizando un pequeño bloque de script incrustado en el código HTML de la página. Desempeña el papel de un caché y contiene información sobre las solicitudes que el servidor agregará al caché (esto, en forma simplificada, se muestra a continuación).
<script type="text/javascript">
Después de restablecer el código HTML en el navegador, el servidor puede ejecutar independientemente las solicitudes de API. Después de recibir respuestas a estas solicitudes, el servidor volcará los datos JSON a la página en forma de una etiqueta de script que contiene estos datos. Cuando el navegador recibe y analiza un fragmento similar del código HTML de la página, esto conducirá al hecho de que los datos caerán en el caché JSON. Lo más importante aquí es que el navegador mostrará la página progresivamente, ya que recibe fragmentos de la respuesta (es decir, los bloques de scripts terminados se ejecutarán a medida que lleguen al navegador). Esto significa que es bastante posible generar simultáneamente grandes cantidades de datos en el servidor y soltar bloques de script en la página tan pronto como los datos correspondientes estén listos. Estas secuencias de comandos se ejecutarán inmediatamente en el cliente. Esta es la base del sistema BigPipe utilizado por Facebook. Allí, muchos localizadores independientes se cargan en paralelo en el servidor y se transmiten al cliente a medida que están disponibles.
<script type="text/javascript"> window.__dataLoaded('/my/api/path', {
Cuando el script del cliente está listo para solicitar los datos que necesita, en lugar de ejecutar la solicitud XHR, primero verifica el caché JSON. Si el caché ya tiene los resultados de la consulta, el script recibe inmediatamente lo que necesita. Si la solicitud está en progreso, el script está esperando los resultados.
function queryAPI(path) { const cacheEntry = window.__data[path]; if (!cacheEntry) {
Todo esto lleva al hecho de que el proceso de carga de la página se convierte en el mismo que en el siguiente diagrama.
El proceso de cargar una página en una situación en la que el navegador participa activamente en la preparación de datos para el clienteSi compara esto con la forma más fácil de cargar páginas, resulta que el servidor y el cliente ahora pueden realizar más tareas en paralelo. Esto reduce el tiempo de inactividad durante el cual el servidor y el cliente esperan el uno al otro.
Esta optimización ha tenido un efecto muy positivo en nuestro sistema. Entonces, en los navegadores de escritorio, la carga de la página comenzó a completarse un 14% más rápido que antes. Y en los navegadores móviles (debido a retrasos más largos en las redes móviles) la página comenzó a cargarse un 23% más rápido.
Estimados lectores! ¿Planea utilizar la metodología para optimizar la formación de páginas web discutidas aquí en sus proyectos?
