Представьте, что вы открываете страницу, и вместо того, чтобы ждать, пока она загрузится целиком, вы сразу же видите её очертания. Сначала появляется общий каркас, затем постепенно подтягиваются детали — контент, изображения, комментарии. Такая модель уже давно привычна для изображений в формате Progressive JPEG. Но почему бы не применить эту логику и к JSON, основному формату передачи данных в веб-приложениях?
🐢 JSON: почему медленно — значит привычно?
Классический подход передачи данных с сервера клиенту прост и прямолинеен: JSON-объект отправляется целиком. Клиент не может начать обработку до тех пор, пока последний байт не прилетит и JSON не будет полностью распарсен.
Представьте ситуацию:
{
"header": "Добро пожаловать в блог!",
"post": {
"content": "Это моя статья",
"comments": ["Первый комментарий", "Второй комментарий"]
},
"footer": "Надеюсь, вам понравится"
}
Даже если заголовок и футер готовы мгновенно, а комментарии грузятся медленно из-за долгого запроса к базе, вам придётся ждать полной загрузки. Кажется не слишком рациональным, правда?
🚧 Стриминг — быстрый, но «ломанный»
Решением может стать стриминг JSON, где данные отправляются по частям, и клиент начинает обработку до окончания передачи всего файла. Но и тут не всё гладко:
- 🧩 JSON может прийти неполным, и у вас просто не будет нужных полей.
- 🕸️ Неясно, будет ли продолжение у массива или объекта.
- 🚨 Приложение рискует постоянно обрабатывать «невалидные» данные.
В итоге подход используется редко, только в специфических кейсах, вроде логов или потоковых данных.
🌳 Progressive JSON: потоковая магия с placeholders
Авторы идеи Progressive JSON предлагают принципиально иной подход — передавать JSON не по порядку (depth-first), а слоями (breadth-first). Вместо данных сразу отправляются плейсхолдеры, которые затем постепенно заменяются реальными значениями.
Например, вместо отправки сразу всего объекта:
{
"header": "Добро пожаловать",
"post": "Статья",
"footer": "Футер"
}
Сначала отправляется структура с плейсхолдерами:
jsonCopyEdit{
"header": "$1",
"post": "$2",
"footer": "$3"
}
А затем данные поступают по мере готовности:
/* $1 */
"Добро пожаловать"
/* $3 */
"Футер"
/* $2 */
{
"content": "$4",
"comments": "$5"
}
/* и так далее */
Клиент же заменяет плейсхолдеры на Promises и работает с ними асинхронно, постепенно наполняя структуру:
{
header: "Добро пожаловать",
post: new Promise(), // пока не готово
footer: "Футер"
}
Это значительно ускоряет восприятие данных пользователем и позволяет более интеллектуально управлять загрузкой контента.
💡 Как это работает технически?
За прогрессивной передачей JSON стоят несколько технических особенностей:
- 🔗 Promises и асинхронность: на клиенте JSON-данные «разворачиваются» через JavaScript-промисы. Это значит, что приложение не блокируется в ожидании всех данных, а загружает контент по мере готовности.
- 🔄 Гибкое пакетирование: Сервер может группировать данные и отправлять их не обязательно в том порядке, как они были запрошены. Например, медленные комментарии не будут тормозить быструю шапку и подвал страницы.
- 🔗 Outlining и Dedupe: Progressive JSON позволяет выделять часто используемые объекты в отдельные фрагменты, тем самым снижая повтор данных и экономя трафик.
🎯 Применение на практике: React Server Components
Идея Progressive JSON активно используется в React Server Components (RSC). Благодаря этому React-приложения загружаются намного эффективнее:
- 🖥️ Скелет интерфейса загружается моментально.
- ⏳ Контент и комментарии подгружаются по мере их готовности, плавно раскрываясь для пользователя.
- 🎨 <Suspense> API позволяет контролировать, как именно появляются данные, обеспечивая приятный пользовательский опыт без скачков интерфейса.
Например, в React можно сделать так, что пользователь сначала увидит заголовок и футер, а комментарии будут отображаться позже, с красивым эффектом загрузки.
📈 А нужно ли всем Progressive JSON?
Конечно, такой подход полезен далеко не всегда. Для простых и небольших JSON-объектов это может быть излишним усложнением. Но Progressive JSON идеален там, где:
- 🔥 Данные большие и разнородные по времени генерации.
- 🚄 Интерфейс требует немедленной реакции на любые поступающие данные.
- 🎯 Критически важна воспринимаемая скорость загрузки контента.
Автор оригинальной статьи Дэн Абрамов предлагает шире взглянуть на эту технологию и использовать её там, где медленные части могут тормозить всё остальное.
Лично я считаю Progressive JSON отличным развитием идеи «интеллектуальной загрузки». В эпоху, когда пользователи нетерпеливы, а приложения перегружены данными, подобные подходы просто необходимы. Важно, чтобы такие инновации становились частью повседневной разработки, улучшая восприятие и скорость современных веб-приложений.