Acelerar el análisis de JSON grandes
En resumen: Optimizar en el orden equivocado hace inútil cada cambio de biblioteca. Mide red, análisis y renderizado por separado; después reduce análisis, encoge cargas útiles y haz streaming.

En resumen: mide por separado red, análisis y renderizado primero —la mayoría de los «análisis lentos» resultan ser renderizados lentos— y luego sube la escalera en orden: menos análisis, cargas útiles más pequeñas, streaming, un worker y, al final, un formato binario.
No empieces cambiando bibliotecas. Añade un temporizador y normalmente descubrirás que el problema es el renderizado.
Paso uno: mide las etapas
const t0 = performance.now();
const response = await fetch(url);
const text = await response.text();
const t1 = performance.now();
const data = JSON.parse(text);
const t2 = performance.now();
render(data);
const t3 = performance.now();
| Etapa dominante | Problema real | Corrección |
|---|---|---|
| Red | Carga útil demasiado grande | Selección de campos, paginación, compresión |
JSON.parse |
Entrada realmente grande | Menos análisis, streaming, worker |
| Renderizado | Decenas de miles de nodos a la vez | Lista virtual, paginación, plegado |
Los navegadores modernos analizan 1 MB en unos 5–15 ms y 10 MB en 80–150 ms. Si 10 MB tarda dos segundos, JSON.parse no es tu cuello de botella.
Paso dos: analiza menos
La victoria más barata, y la más pasada por alto.
- Deja de analizar la misma carga útil repetidamente. Diez componentes que llaman cada uno a
JSON.parse(localStorage.getItem(...))son diez análisis. Guarda en caché una vez a nivel de módulo. - Deja de usar
JSON.parse(JSON.stringify(x))para copias profundas. Cuesta más del doble del volumen de datos;structuredCloneno. - No analices en el hilo principal y luego envíes el objeto a un worker.
postMessagelo clona de nuevo. Envía el texto sin procesar y deja que el worker lo analice. - Pide menos campos. Si la interfaz necesita tres propiedades, la API no debería enviar trescientas.
Paso tres: encoge la carga útil
Paginación por page/size, cursores en lugar de un offset profundo, campos de resumen en los endpoints de lista. Normalmente supera a todas las optimizaciones de frontend juntas, porque reduce red, análisis y memoria a la vez.
Paso cuatro: streaming
Cuando los datos deben procesarse en su totalidad y realmente son grandes:
import { parser } from 'stream-json';
import { streamArray } from 'stream-json/streamers/StreamArray';
const pipeline = fs.createReadStream('big.json').pipe(parser()).pipe(streamArray());
for await (const { value } of pipeline) {
await handleOne(value);
}
Más código, y sin acceso aleatorio: solo apto para procesamiento registro a registro.
Paso cinco: sácalo del hilo principal
El análisis es rápido pero bloqueante. Ponlo en un worker y pasa el texto, no el objeto analizado, o el clonado estructurado duplica el coste.
Paso seis: cambia el formato, al final
Para tráfico interno que de forma constante son decenas de megabytes, NDJSON fluye de forma natural, y Protobuf o MessagePack son más pequeños y rápidos. Ambos son cambios de protocolo que requieren coordinación.
Qué no hacer
evalde JSON: inseguro y no más rápido- Convertir JSON a cadena para incrustarlo en JSON: duplica el tamaño
- Analizar cientos de miles de cadenas diminutas en un bucle: agrúpalas
FAQ
¿Cómo sé si el cuello de botella es el análisis o el renderizado?
Cronometra por separado la petición, la lectura del texto, JSON.parse y el renderizado con performance.now(), y trata la etapa más grande como el cuello de botella real. Los navegadores modernos analizan 1 MB en unos 5–15 ms y 10 MB en 80–150 ms, así que una carga útil de 10 MB que tarda dos segundos rara vez es un problema de JSON.parse.
¿Por qué cambiar de biblioteca normalmente no ayuda?
JSON.parse ya es nativo y rápido; la mayoría de los «análisis lentos» vienen de análisis repetidos o de renderizar decenas de miles de nodos a la vez. Cambiar de biblioteca gana un 10–30 %, mientras que eliminar un análisis completo a menudo ahorra la mitad.
¿Debería mover el análisis a un Web Worker?
Muévelo a un worker cuando el análisis bloquee el hilo principal y la página se congele o las animaciones pierdan fotogramas. Pasa el texto sin procesar en lugar del objeto analizado, porque si no, el clonado estructurado de postMessage duplica el coste.