- Al igual que un JPEG progresivo, los datos JSON también pueden enviarse primero en un estado incompleto para que el cliente vaya aprovechando gradualmente todo el contenido
- El método tradicional de parseo de JSON tiene el problema de la ineficiencia: no se puede hacer nada hasta que se reciba por completo toda la información
- Con un enfoque breadth-first, los datos se dividen en varios chunks (partes); las secciones que aún no están listas se representan como Promise y se van completando progresivamente conforme se preparan, de modo que el cliente puede usar incluso datos incompletos
- Este concepto es la innovación central de React Server Components (RSC), y con
<Suspense> se controlan los estados de carga por etapas de forma intencional
- Al separar el streaming de datos del flujo intencional de carga de la UI, se puede ofrecer una experiencia de usuario más flexible
La idea del JPEG progresivo y el JSON progresivo
- Un JPEG progresivo, en lugar de cargar la imagen de arriba hacia abajo de una sola vez, primero muestra la imagen completa en un estado borroso y luego la va haciendo más nítida
- De forma similar, al aplicar un enfoque progresivo al envío de JSON, es posible usar parte de los datos de inmediato sin esperar a que todo esté completo
- En una estructura de datos JSON de ejemplo, el enfoque habitual solo permite hacer el parseo una vez recibidos todos los bytes hasta el último
- Por eso, el cliente tiene que esperar a que todo se termine de enviar, incluso las partes lentas del servidor (por ejemplo, cargar
comments desde una base de datos lenta), lo cual es un estándar actual muy ineficiente
Límites de los parsers de JSON en streaming
- Si se introduce un parser de JSON en streaming, es posible generar un árbol de objetos de datos incompleto (intermedio)
- Sin embargo, cuando los campos de cada objeto (por ejemplo,
footer o una lista de varios comment) llegan solo de forma parcial, surgen problemas de incompatibilidad de tipos y dificultad para saber qué ya está completo, lo que reduce su utilidad
- Al igual que con el renderizado HTML en streaming, procesar el stream en orden hace que una sola parte lenta retrase todo el resultado, exactamente el mismo problema
- Esta es una de las razones por las que el JSON en streaming rara vez se aprovecha en la práctica
Propuesta de estructura para Progressive JSON
- En vez del streaming tradicional en profundidad, es decir, enviar recorriendo internamente la estructura de árbol hasta sus niveles inferiores, se propone un enfoque breadth-first (por amplitud)
- Primero se envía solo el objeto de nivel superior, y los valores inferiores se dejan como placeholders similares a Promise, para luego ir completándolos en chunks separados conforme estén listos
- Por ejemplo, cada vez que el servidor termina de cargar datos de forma asíncrona, envía el chunk correspondiente, y el cliente puede usar únicamente lo que ya esté disponible
- Esto permite recibir datos de forma asíncrona (carga temprana) sin tener que esperar a que varias partes lentas terminen de procesarse por completo
- Si el cliente se diseña para tolerar bien la recepción no secuencial por chunks y la recepción parcialmente secuencial, el servidor puede aplicar con flexibilidad distintas estrategias de división en chunks
Inlining y Outlining: transmisión eficiente de datos
- Un formato de streaming de JSON progresivo puede, incluso para objetos reutilizados (por ejemplo, referenciar el mismo
userInfo en varios lugares), extraerlos aparte en un solo chunk sin duplicarlos y permitir la misma referencia desde cada posición
- Al separar solo las partes lentas y enviarlas como placeholders, mientras el resto se completa de inmediato, se logra un flujo de datos más eficiente
- Cuando el mismo objeto aparece varias veces, es posible enviarlo una sola vez y reutilizarlo (Outlining)
- De esta manera, incluso las referencias circulares (estructuras en las que un objeto se referencia a sí mismo) pueden serializarse de forma natural como referencias indirectas entre chunks, sin las dificultades típicas del JSON convencional
Implementación de streaming progresivo en React Server Components (RSC)
- Un ejemplo representativo de aplicación real de este modelo de streaming progresivo de JSON es React Server Components
- El servidor usa una estructura en la que carga datos externos (por ejemplo,
Post, Comments) de forma asíncrona
- En el cliente, las partes que todavía no han llegado se mantienen como Promise, y la UI se renderiza progresivamente en el orden en que van estando listas
- React usa
<Suspense> para definir estados de carga intencionales
- Para evitar saltos visuales innecesarios en la experiencia de usuario, no se muestra de inmediato el estado Promise (el hueco), sino que se puede escenificar una carga por etapas con el fallback de
<Suspense>
- Aunque los datos lleguen rápido, el desarrollador puede controlar que la UI real se vaya mostrando progresivamente según las etapas diseñadas
Resumen e implicaciones
- La innovación central de React Server Components está en hacer streaming progresivo de las props del árbol de componentes desde la parte exterior hacia adentro
- Por eso, no hace falta esperar a que el servidor tenga todos los datos completamente listos; se pueden mostrar antes las partes importantes y controlar con más detalle los estados de espera de carga
- No solo hace falta el streaming en sí, sino también soporte estructural como un modelo de programación que lo aproveche (por ejemplo,
<Suspense> de React)
- Con ello, se pueden aliviar cuellos de botella de los métodos de transmisión tradicionales, como el problema de que una sola parte lenta retrase todo
1 comentarios
Comentarios de Hacker News
$1del artículo por un URI, quizá ni siquiera necesites un servidor (la mayoría de los casos no requieren SSR dinámico obligatoriamente)null; hace falta información adicional sobre qué datos siguen pendientesJSON.parse