Я заметил, что метод reactDOM.renderToString()
начинает значительно замедляться при рендеринге большого дерева компонентов на сервере.
Фон
Немного предыстории. Система является полностью изоморфным стеком. Компонент высшего уровня App
отображает шаблоны, страницы, элементы dom и другие компоненты. Посмотрев код реакции, я обнаружил, что он рендерит ~ 1500 компонентов (это относится к любому простому тегу dom, который рассматривается как простой компонент, <p>this is a react component</p>
.
В разработке рендеринг ~ 1500 компонентов занимает ~ 200-300мс. Удалив некоторые компоненты, я смог получить ~ 1200 компонентов для визуализации за ~ 175-225 мс.
В производстве renderToString для ~ 1500 компонентов занимает около 50-200 мс.
Время кажется линейным. Ни один из компонентов не является медленным, скорее это сумма многих.
Проблема
Это создает некоторые проблемы на сервере. Длительный метод приводит к увеличению времени ответа сервера. TTFB намного выше, чем должен быть. При вызовах API и бизнес-логике ответ должен составлять 250 мс, а при рендеринге 250 мс он удваивается! Плохо для SEO и пользователей. Кроме того, будучи синхронным методом, renderToString()
может блокировать сервер узлов и создавать резервные копии последующих запросов (это можно решить, используя 2 отдельных сервера узлов: 1 в качестве веб-сервера и 1 в качестве службы, предназначенной исключительно для реагирования на рендеринг).
Попытки
В идеале для рендеринга ToString в производстве потребуется 5-50 мс. Я работал над некоторыми идеями, но я не совсем уверен, какой будет лучший подход.
Идея 1: Кэширование компонентов
Любой компонент, помеченный как "статический", может быть кэширован. Сохраняя кэш с визуализированной разметкой, renderToString()
может проверять кэш перед визуализацией. Если он находит компонент, он автоматически захватывает строку. Выполнение этого на компоненте высокого уровня сохранит монтирование всех вложенных дочерних компонентов. Вам нужно заменить rootID реагирующей разметки компонента rootID на текущий rootID.
Идея 2: Маркировка компонентов как простых/немых
Определяя компонент как "простой", реакция должна пропускать все методы жизненного цикла при рендеринге. React уже делает это для основных компонентов реагирования (<p/>
, <h1/>
и т.д.). Было бы неплохо расширить пользовательские компоненты для использования той же оптимизации.
Идея 3: Пропустить компоненты при рендеринге на стороне сервера
Компоненты, которые не должны быть возвращены сервером (без значения SEO), могут быть просто пропущены на сервере. Как только клиент загрузится, установите флаг clientLoaded
на true
и передайте его вниз для принудительного повторного рендеринга.
Закрытие и другие попытки
Единственное решение, которое я реализовал до сих пор, - это уменьшить количество компонентов, отображаемых на сервере.
Вот некоторые проекты, на которые мы смотрим:
- React-dom-stream (все еще работает над реализацией этого для теста)
- Встроенные элементы Babel (кажется, это похоже на идею 2)
Кто-нибудь сталкивался с подобными проблемами? Что ты смог сделать? Благодарю.