Streaming и прогрессивная загрузка — ключевые техники оптимизации рендеринга на стороне сервера, которые позволяют существенно сократить время до отображения первого содержимого и улучшить пользовательский опыт.
Inferno изначально проектировался с упором на производительность. Серверный рендеринг (SSR) создаёт HTML на сервере, позволяя браузеру получать уже готовый контент. Стандартный подход SSR предполагает генерацию полного HTML перед отправкой ответа, что может создавать задержки при рендеринге больших приложений.
Streaming SSR решает эту проблему, разбивая HTML на фрагменты и отправляя их по мере готовности. Это уменьшает задержку первой отрисовки и позволяет пользователю видеть контент раньше, чем весь HTML полностью сформирован.
renderToString и
renderToStaticMarkup
Традиционные функции SSR создают полностью сформированную строку HTML. Например:
import { renderToString } from 'inferno-server';
import App from './App';
const html = renderToString(<App />);
Здесь html будет содержать весь DOM-продукт приложения
сразу. Этот метод прост, но не поддерживает прогрессивную
загрузку.
renderToStream
Inferno позволяет использовать потоковую генерацию HTML через
renderToStream. Эта функция возвращает ReadableStream,
который можно передавать напрямую в ответ сервера. Пример использования
с Node.js:
import { renderToStream } from 'inferno-server';
import App from './App';
import express from 'express';
const app = express();
app.get('/', (req, res) => {
const stream = renderToStream(<App />);
res.setHeader('Content-Type', 'text/html; charset=utf-8');
stream.pipe(res);
});
В отличие от renderToString, браузер начинает получать
HTML сразу, пока сервер продолжает формировать оставшуюся часть
документа.
Прогрессивная загрузка тесно связана с lazy-loading компонентов. В Inferno это реализуется через динамический импорт и поддержку Suspense-like паттернов. Основная идея — разбивать приложение на отдельные чанки и загружать их по мере необходимости.
Пример динамического импорта компонента:
import { Component, lazy } from 'inferno';
const HeavyComponent = lazy(() => import('./HeavyComponent'));
class App extends Component {
render() {
return (
<div>
<h1>Главный экран</h1>
<HeavyComponent />
</div>
);
}
}
При серверном рендеринге потоковый рендеринг может отдавать базовую оболочку страницы сразу, а динамически загружаемый компонент подключается и рендерится отдельно после загрузки скриптов на клиенте.
Сочетание этих подходов позволяет:
Пример потокового SSR с прогрессивной загрузкой:
import express from 'express';
import { renderToStream } from 'inferno-server';
import App from './App';
const server = express();
server.get('/', (req, res) => {
res.setHeader('Content-Type', 'text/html; charset=utf-8');
res.write('<!DOCTYPE html><html><head><title>Inferno Streaming</title></head><body>');
const stream = renderToStream(<App />);
stream.on('data', chunk => res.write(chunk));
stream.on('end', () => res.end('</body></html>'));
});
Здесь базовая структура страницы формируется сразу, а содержимое приложения отдается потоково.
hydrate или
hydrateRoot, связывая серверный DOM с реактивностью.Streaming и прогрессивная загрузка в Inferno обеспечивают гибкую архитектуру рендеринга, сочетающую преимущества SSR и клиентского рендеринга. Потоковая генерация HTML и динамическая подгрузка компонентов позволяют создавать высокопроизводительные приложения с минимальными задержками для конечного пользователя, сохраняя SEO-дружелюбность и улучшая опыт взаимодействия.