- Assim como no JPEG progressivo, os dados em JSON também podem ser enviados primeiro de forma incompleta, permitindo que o cliente aproveite gradualmente todo o conteúdo
- O método tradicional de parsing de JSON tem a ineficiência de não permitir nenhuma ação até que todos os dados sejam recebidos por completo
- Com uma abordagem breadth-first, os dados são divididos em vários chunks (partes), e as seções ainda não prontas são representadas como Promises e preenchidas progressivamente conforme ficam disponíveis, permitindo que o cliente use até mesmo dados incompletos
- Esse conceito é a principal inovação dos React Server Components (RSC), e o
<Suspense> controla estados de carregamento intencionais em etapas
- Ao separar o streaming de dados do fluxo intencional de carregamento da UI, é possível oferecer uma experiência do usuário mais flexível
A ideia de JPEG progressivo e JSON progressivo
- Um JPEG progressivo, em vez de carregar a imagem de uma vez só de cima para baixo, primeiro mostra a imagem inteira de forma borrada e depois vai ficando mais nítida aos poucos
- De forma semelhante, ao aplicar uma abordagem progressiva à transmissão de JSON, é possível usar parte dos dados imediatamente, sem esperar que tudo esteja completo
- Em uma estrutura de dados JSON de exemplo, o método comum só permite o parsing depois que o último byte tiver sido recebido
- Por causa disso, o cliente precisa esperar até que tudo seja transmitido, inclusive as partes lentas do servidor (por exemplo, carregar
comments de um banco de dados lento), o que é um padrão atual bastante ineficiente
Limites de um parser de JSON por streaming
- Ao introduzir um parser de JSON por streaming, é possível criar uma árvore de objetos intermediária e incompleta
- Porém, quando apenas parte dos campos de cada objeto é transmitida (por exemplo,
footer, ou uma lista com vários comment), surgem problemas de incompatibilidade de tipos e dificuldade para identificar o grau de completude, reduzindo sua utilidade
- Assim como no render streaming de HTML, ao processar o stream em ordem, uma parte lenta acaba atrasando o resultado inteiro
- Esse é um dos motivos pelos quais o uso de JSON por streaming não é comum
Proposta de estrutura para Progressive JSON
- Em vez do streaming tradicional em profundidade, isto é, percorrendo e transmitindo até os níveis inferiores da árvore, adota-se uma abordagem breadth-first (em largura)
- Primeiro, apenas o objeto de nível superior é enviado, enquanto os valores abaixo ficam como placeholders semelhantes a Promises, sendo preenchidos em chunks separados conforme ficam prontos
- Por exemplo, sempre que o servidor termina o carregamento assíncrono de dados, ele envia o chunk correspondente, e o cliente pode usar apenas o que já estiver disponível
- Isso permite recebimento assíncrono de dados (carregamento antecipado) e evita a necessidade de esperar pelo término de várias partes lentas antes de aproveitar qualquer resultado
- Se o cliente for projetado para lidar bem com recebimento não sequencial por chunk e parcialmente sequencial, o servidor pode aplicar com flexibilidade várias estratégias de divisão em chunks
Inlining e Outlining: transmissão de dados eficiente
- Um formato de streaming de JSON progressivo pode, sem duplicar armazenamento, extrair em um chunk separado objetos reutilizados (por exemplo, o mesmo
userInfo referenciado em vários lugares) e permitir a mesma referência em cada posição
- Apenas as partes lentas são separadas e enviadas como placeholders, enquanto o restante é preenchido imediatamente, criando um stream de dados mais eficiente
- Quando o mesmo objeto aparece várias vezes, é possível enviá-lo uma única vez e reutilizá-lo (Outlining)
- Dessa forma, até referências circulares (estruturas em que um objeto referencia a si mesmo) podem ser serializadas naturalmente por meio de referências indiretas entre chunks, sem a dificuldade típica do JSON comum
A implementação de streaming progressivo nos React Server Components (RSC)
- Os React Server Components reais são um exemplo representativo de aplicação do modelo de streaming progressivo de JSON
- O servidor usa uma estrutura que carrega dados externos (por exemplo, Post e Comments) de forma assíncrona
- No cliente, as partes que ainda não chegaram ficam como Promises e a UI é renderizada progressivamente na ordem em que ficam prontas
- O React usa
<Suspense> para definir estados de carregamento intencionais
- Para evitar saltos visuais desnecessários na experiência do usuário, o estado de Promise (os “buracos”) não é mostrado imediatamente; em vez disso, o fallback de
<Suspense> permite encenar o carregamento em etapas
- Mesmo que os dados cheguem rapidamente, o desenvolvedor pode controlar a exposição progressiva da UI de acordo com as etapas planejadas
Resumo e implicações
- A principal inovação dos React Server Components está em fazer streaming progressivo das props da árvore de componentes de fora para dentro
- Portanto, não é necessário esperar que o servidor prepare todos os dados por completo; é possível mostrar primeiro as partes principais e controlar com mais precisão os estados de espera de carregamento
- Não basta apenas o streaming em si; também é necessário suporte estrutural, como um modelo de programação que o aproveite (como o
<Suspense> do React)
- Com isso, é possível aliviar gargalos dos métodos tradicionais de transmissão, como o problema de uma parte lenta dos dados atrasar todo o restante
1 comentários
Opiniões do Hacker News
JSON.parse