Прискорення розбору великого JSON
Головне: Оптимізація в неправильному порядку робить будь-яку заміну бібліотеки марною. Виміряйте мережу, розбір і відображення окремо, потім скоротіть розбори, зменшіть навантаження й переходьте на потокову обробку.

Коротко: спершу виміряйте мережу, розбір і відображення окремо — більшість «повільного розбору» виявляється повільним відображенням — потім піднімайтеся драбиною за порядком: менше розборів, менші навантаження, потокова обробка, worker, і двійковий формат останнім.
Не починайте із заміни бібліотек. Додайте один таймер — і зазвичай виявите, що проблема у відображенні.
Крок перший: виміряйте етапи
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();
| Домінантний етап | Справжня проблема | Виправлення |
|---|---|---|
| Мережа | Навантаження завелике | Вибір полів, пагінація, стиснення |
JSON.parse |
Справді великий вхід | Менше розборів, потокова обробка, worker |
| Відображення | Десятки тисяч вузлів одразу | Віртуальний список, сторінки, згортання |
Сучасні браузери розбирають 1 МБ приблизно за 5–15 мс, а 10 МБ — за 80–150 мс. Якщо 10 МБ займає дві секунди, JSON.parse — не ваше вузьке місце.
Крок другий: розбирайте менше
Найдешевший виграш і найбільш проґавлений.
- Припиніть повторно розбирати те саме навантаження. Десять компонентів, кожен викликає
JSON.parse(localStorage.getItem(...)), — це десять розборів. Кешуйте один раз на рівні модуля. - Припиніть використовувати
JSON.parse(JSON.stringify(x))для глибоких копій. Це коштує більш ніж удвічі обсяг даних;structuredClone— ні. - Не розбирайте на головному потоці й потім не надсилайте обʼєкт у worker.
postMessageклонує його знову. Надсилайте сирий текст і дозвольте worker розібрати. - Просіть менше полів. Якщо UI потрібні три властивості, API не має надсилати триста.
Крок третій: зменшіть навантаження
Пагінація за page/size, курсори замість глибокого offset, підсумкові поля в кінцевих точках списків. Зазвичай це краще за всі фронтенд-оптимізації разом, бо зменшує мережу, розбір і памʼять одночасно.
Крок четвертий: потокова обробка
Коли дані треба обробити цілком і вони справді великі:
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);
}
Більше коду й без довільного доступу — підходить лише для обробки запис за записом.
Крок пʼятий: перенесіть із головного потоку
Розбір швидкий, але блокуючий. Покладіть його в worker і передавайте текст, а не розібраний обʼєкт, інакше структурне клонування подвоїть ціну.
Крок шостий: змініть формат, останнім
Для внутрішнього трафіку, що стабільно становить десятки мегабайт, NDJSON природно потоковий, а Protobuf чи MessagePack менші й швидші. Обидва — зміни протоколу, що потребують узгодження.
Не робіть
evalJSON: небезпечно й не швидше- Серіалізувати JSON, щоб вбудувати його в JSON: подвоює розмір
- Розбирати сотні тисяч крихітних рядків у циклі: пакетуйте їх
Часті питання
Як дізнатися, розбір чи відображення є вузьким місцем?
Зміряйте окремо час запиту, читання тексту, JSON.parse і відображення через performance.now() і вважайте найбільший етап справжнім вузьким місцем. Сучасні браузери розбирають 1 МБ приблизно за 5–15 мс, а 10 МБ — за 80–150 мс, тож навантаження на 10 МБ, що займає дві секунди, рідко є проблемою JSON.parse.
Чому заміна бібліотек зазвичай не допомагає?
JSON.parse уже нативний і швидкий; більшість «повільного розбору» походить із повторного розбору або відображення десятків тисяч вузлів одразу. Заміна бібліотеки купує 10–30%, тоді як видалення одного повного розбору часто дає половину.
Чи переносити розбір у Web Worker?
Переносьте у worker, коли розбір блокує головний потік і сторінка замерзає або анімації втрачають кадри. Передавайте сирий текст, а не розібраний обʼєкт, інакше структурне клонування postMessage подвоїть ціну.