TGViewer
Сергей Мелюков Сергей Мелюков @smelukov_dev · 646 subscribers
Post #70 930
Привет! Небольшая заметка о том, как я затаскивал поддержку больших статов в генерируемые Статоскопом HTML-отчеты.
Как мы с вами уже знаем, у JS-движков есть ограничение на максимальный размер строки (например 512мб для V8)
Это значит, что при попытке получить строку большего размера, мы получим ошибку RangeError: Invalid string length
Очевидно, что для статов размером больше 512mb тот же JSON.parse работать не будет, но как раз JSON.parse нам и нужен.
Обойти ограничение можно при помощи поточного JSON-парсера. Такому парсеру нужен источник строки, который будет отдавать ее не целиком, а кусочками (например по 64кb). По мере того, как парсер получает кусочки, он пытается их распарсить - превратить в объект. Очевидно, что этот объект растет по мере парсинга. Смысл в том, что мы не обрабатываем большие строки, а следовательно, у нас не возникает исключения RangeError, а сам объект путь себе растет пока хватает оперативной памяти.
Ну хорошо, делаю первый подход - взял поточный парсер от @rdvornov, формирую HTML и инъекчу в него код вроде такого:

const chunks = [
сюда вставляю большой JSON порубленный на строки по 64kb
];
const data = await jsonExt.parseChunked(() => chunks);
Statoscope(data);


Запускаю - не работает, браузер просто зависает 🤔
Методом проб и ошибок выяснил, что бразуер просто не переваривает такой большой тег скрипт (несколько сот мегабайт). Никакой особо полезной информации я по этому ограничению не нашел, но стало ясно, что теперь я воткнулся в проблему лимитов самого браузера. Стал думать что здесь можно сделать. Пришла идея попилить на куски не только JSON, но и теги script:


<script>
chunks.push(КУСОК_JSON)
</script>
<script>
chunks.push(СЛЕДУЮЩИЙ_КУСОК_JSON)
</script>

..... здесь еще много подобных тегов script

<script>
const data = await jsonExt.parseChunked(() => chunks);
Statoscope(data);
</script>


Запустил, заработало! Теперь я смог обойти и ограничение на JSON.parse и ограничение браузера на размер тега script.
Учитывая то, что загружать в отчет можно сразу несколько файлов со статами, например, для сравнения сборок, предусмотрел пуш чанка по идентификатору стата:


<script>
api.pushChunk("stat1.json", КУСОК_JSON)
</script>

<script>
api.pushChunk("stat2.json", КУСОК_JSON)
</script>

<script>
api.pushChunk("stat1.json", КУСОК_JSON)
</script>


Таким образом даже не важен порядок, в котором статы сбрасываются в отчет.

Прошло какое-то время и @rdvornov задал интересный вопрос: "Слушай, а почему бы не использовать теги script не как скрипт, а как текст, тогда можно было бы сэкономить на парсинге?"
И действительно, если сказать браузеру, что содержимое script - это не скрипт, а текст, то браузер не будет тратить время на парсинг сожержимого. А, на минуточку, 64kb x Nk тегов script - это ощутимо.

В итоге получилось что-то вроде:


<script type="text/plain" data-id="stat1.json">КУСОК_JSON</script>
<script type="text/plain" data-id="stat1.json">КУСОК_JSON</script>

......

<script>
for (const element of document.querySelectorAll('script')) {
api.pushChunk(element.dataset.id, element.textContent);
}

const data = await jsonExt.parseChunked(() => api.getChunks());
Statoscope(data);
</script>


Там конечно чуть сложнее, полную версию изменений можно посмотреть тут

Итог этой простой манипуляции такой: время загрузки отчета со статами в 650mb сократилась с 21 секунды до 14 (профит в 33%!!!)
Мораль: почти всегда можно что-то придумать, чтобы стало лучше (даже когда кажется, что нельзя) 😉
GitHub (feat): improve HTML-report loading time · smelukov/statoscope@9b58295 Analyzes webpack stats and shows detailed info about it on the screen. - smelukov/statoscope
More from @smelukov_dev
  1. Jun 14, 2026Подумал тут про покрытие тестами кода, который написала модель Есть отдельный интересный к…
  2. May 15, 2026Кстати, если вы когда-нибудь озадачивались подсчетом ресурсов для развертывания LLM локаль…
  3. May 15, 2026В чем произошла заруба: Среди прочего, я хочу понимать какие MCP были запущены и сколько о…
  4. May 15, 2026Подумал: почему бы не писать о том, что делаю прямо сейчас и с чем сталкиваюсь 🙂 Я придер…
  5. Apr 13, 2026ИИ победил! Готовлю кое-что интересное. Интересно, что Ведьмак и Статоскоп поделили степен…
  6. Apr 10, 2026Post #126
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →