Автономный предварительный рендеринг OPR: 0 затрат на доступ, сравнимый с эффектом SSR

внешний интерфейс



Если отсчитывать первые в отрасли схемы оптимизации экрана на данном этапе, то в основном это: схемы SSR, Prerender, CSR и др. Идея этих схем состоит в том, чтобы поставить процесс рендеринга перед традиционным рендерингом клиента SPA, а традиционный Методы оптимизации производительности собраны из проекта SPA, очень мало из-за фатального недостатка самого SPA:


СПА решение


На первое экранное исполнение SPA-проекта мы обращали внимание и постоянно исследовали в течение длительного времени, за этот период мы перепробовали множество решений, в том числе:


  • С точки зрения уменьшения размера кода: оптимизация веб-пакетов, оптимизация упаковки, встряхивание деревьев и т. д.

  • С точки зрения сокращения HTTP-запросов: слияние интерфейсов, загрузка по запросу, отложенная загрузка и другие методы сокращения запросов.

  • С точки зрения кеширования: автономные пакеты, различное использование кеша http и браузеров, предварительный анализ dns, схема dll, схема кеширования интерфейса и т. д.

  • С точки зрения времени сбора данных: webWorker выполняет предварительную выборку данных, процесс ввода маршрута считывает данные и т. д.

  • Начиная с уменьшения размера и количества изображений: используйте веб-изображения, запрашивайте параллельную оптимизацию доменного имени, CSS Sprite и т. д.

Эти решения могут в определенной степени сократить время белого экрана и время первого экрана, но эффект ограничен, и трудно значительно уменьшить данные, как решение SSR, Причина в том, что процесс рендеринга страницы SPA следующим образом:




Как видно из приведенного выше рисунка, процесс белого экрана практически неизбежен, потому что в любом случае, если вы пойдете на оптимизацию объема кода, библиотеки серии Vue и других файлов библиотеки основных классов вам понадобится не менее сотни К, плюс это время файла выполняется (не менее 500 мс), в большинстве случаев у нас есть время белого экрана не менее 1200 мс-1500 мс.


Конечно, мы можем поместить CSS, требуемый скелетным экраном, в HTML, который может отобразить скелетный экран как можно быстрее (но многим ядрам с низкими версиями необходимо загрузить и выполнить полный скрипт для отображения страницы), но это не так. настоящий первый экран.Даже в статистику производительности нельзя залить апгрейд первого экрана.


Так что схема SSR стала нашей спасительной соломинкой:


решение ССР


Давайте посмотрим, как SSR решает эту проблему:



Преимущество SSR-решения в том, что загружаемый браузером HTML уже имеет DOM-структуру и стили, необходимые для рендеринга первого экрана, а время белого экрана практически равно времени загрузки HTML-файла, что меньше, чем у SPA. Значительно улучшен.


Так почему бы нам напрямую не использовать схему SSR?

Есть четыре основные причины:


1. Стоимость реконструкции проекта SSR высока

В стеке технологий Vue есть два основных решения SSR: официальное решение и Nuxt.js, У этих двух решений одинаковые точки:

  • Существующие конфигурации веб-пакетов должны быть заменены двумя вышеуказанными проектами проектов.

  • Все страницы проекта должны выполнять требования метода SSR

  • Данные должны извлекаться в рамках пользовательского жизненного цикла asyncData/preFetch.

  • Данные интерфейса должны управляться с помощью Vuex.

Может быть, вы думаете, что это не сложно.Для нового проекта это не сложно, но для старого проекта вышеупомянутые затраты на трансформацию и тестирование чрезвычайно высоки, поэтому старых проектов по модернизации SSR мало.


2. Производительность SSR зависит от производительности интерфейса

Из принципа SSR вы можете знать, что процесс рендеринга сервера SSR зависит от получения всех данных для начала рендеринга.Если интерфейс задерживается или истечет время ожидания, это также повлияет на производительность первого экрана.


3. Нагрузочная способность ВОРЛ и расширение мощностей могут стать узкими местами

В отрасли почти признано, что грузоподъемность узла хуже, чем у java, и обслуживание статических ресурсов хуже у nginx, и у многих компаний нет достаточной практики и механизмов, гарантирующих быстрое расширение сервера узла. сервера, чтобы противостоять пикам трафика, но ведь это соответствует стоимости.


4. SSR без схемы понижения

После сбоя службы узла страница может сразу перейти к белому экрану.Во многих случаях это не решается перезапуском службы.В конце концов, SSR не похож на SPA, который можно решить или откатить, когда вы видите ошибку в браузере.Вы действительно должны устранить ошибку.Восстановление службы в течение этого периода не может быть легко понижено до плана SPA.


Среди вышеперечисленных причин основной причиной, которая мешает нам использовать SSR, является стоимость преобразования.


Пререндеринг решения



Пререндер реализован на основе плагина webpack prerender-spa-plugin, принцип работы следующий:



Основной принцип заключается в том, чтобы получить доступ к соответствующему маршруту через Puppeteer во время процесса упаковки веб-пакета, получить html и сделать его статическим, а затем развернуть cdn.


Однако данная схема редко используется в промышленности по основным причинам:

  • Статический процесс происходит на этапе построения, и данные, которые пользователи видят при посещении, обречены на устаревание.

  • Это решение основано на использовании маршрутизации на основе истории, что недешево для модернизации и тестирования старых проектов.

  • Существенное увеличение времени компиляции, подумайте об этом.

Из приведенного выше анализа мы видим, что "оптимальным решением" должно быть SSR. Без учета грузоподъемности единственное, что нам мешает, - это стоимость преобразования. Можем ли мы добиться того же эффекта, что и SSR, с меньшими затратами?


Предварительная визуализация в автономном режиме OPR


В ясном небе раздался гром, и был сгенерирован OPR, который мы назвали OPR (Offline Prerender).


Процесс рендеринга OPR:



В отличие от рендеринга SSR на этапе доступа пользователя, OPR представляет собой сервис рендеринга, независимый от процесса доступа пользователя. Он регулярно отображает страницы через Puppeteer и загружает cdn. Страницы, к которым обращаются пользователи, будут чисто статическими страницами, о которых можно сказать, что в сочетании с SSR.и Prerender два варианта.


Отличие от схемы SSR:

  1. Процесс рендеринга не зависит от доступа пользователя, нет нагрузки на сервер, он занимает очень мало ресурсов и может быть выполнен одним сервером.

  2. Страница вряд ли нуждается в каких-либо изменениях

  3. Эффект отображаемой страницы почти такой же, как у SSR.

  4. Можно перейти на план SPA


Отличия от схемы Prerender:

  1. Решить проблему, связанную с тем, что данные схемы Prerender не могут быть своевременно обновлены посредством рендеринга по времени.

  2. Страница вряд ли нуждается в каких-либо изменениях

  3. Не влияет на исходный процесс структурирования проекта


Процесс реализации схемы OPR



Разберем просто:


1 Регулярно посещайте страницу

Сначала мы создаем службу узла и регулярно обращаемся к страницам, которые необходимо отображать, через Puppeteer через механизм расписания.


2 Подождите, пока страница отобразится

Рендеринг страницы — это динамический процесс. Откуда мы знаем, что страница была визуализирована? На самом деле Puppeteer предлагает множество решений, но решение, которое мы в итоге выбрали, — это отслеживать статистику производительности компании и замалчивать время.


3 Скрапинг HTML

Вы должны четко понимать: мы захватываем HTML-код, отображаемый браузером, а не содержимое запрошенного вами файла index.html.

Вы можете понять первое, так как через инструменты разработчика браузера выберите тег html, щелкните правой кнопкой мыши, чтобы скопировать externalHTML.

В последнем случае вы можете просмотреть исходный код html через браузер, там должен быть только пустой dom и несколько тегов

Прежний контент может выглядеть так:



Содержание последнего таково.



На самом деле действие захвата HTML может быть выполнено с помощью одного кода в Puppeteer: page.$eval('html', e => e.outerHTML), но мы проделали большую обработку полученного HTML:


Рендеринг логотипа OPR

Чтобы страница знала, что она отрисовывается с помощью OPR, мы внедрим в HTML переменную: __offline_prerender_data__, эта переменная не только служит идентификатором, но также может использоваться для хранения некоторых специальных данных.


Захват данных интерфейса

Учащиеся, знакомые с процессом SSR, могут знать, что SSR записывает данные, необходимые на этапе рендеринга на стороне сервера, в HTML, а рендеринг на стороне клиента выполняет проверку данных. второй раз как можно скорее Рендеринг (описан ниже).


Такие возможности также могут быть предоставлены в OPR:

Если разработчик устанавливает useDataCache : true в конфигурационном файле, мы будем отслеживать все запросы интерфейса до завершения рендеринга страницы, вводить данные в HTML и внедрять для вас кусок кода, чтобы данные могли быть сохранены, когда HTML выполняется в localStorage для использования некоторыми библиотеками кеша интерфейса


Общий код выглядит следующим образом:


4 Решить проблему адаптации

Среда устройства, которую мы имитируем в server puppeteer, определенно отличается от фактического устройства пользователя, поэтому нам нужно решить проблему адаптации стиля:

а. Вставьте код обновления rem в голову

б. Преобразуйте px на странице в rem

Схема относительно проста, и код здесь не выложен.


5 Удалите бесполезный контент

Мы удалили бесполезный контент из HTML, в том числе:


6 Контраст

Мы ожидаем, что частота обновления cdn уменьшится, поэтому мы сравниваем отображаемый HTML-код с последним отображаемым HTML-кодом. Если содержимое является согласованным, оно не будет отображаться повторно. Существуют две основные ситуации, которые приводят к несогласованному отображению:

a: Во время процесса появляется новая онлайн-страница

В настоящее время адрес

б: данные на странице изменились

  • Нужно выйти в интернет: Данные интерфейса изменились

  • Нет необходимости выходить в интернет: изменения данных, которые не очень важны на странице, такие как обратный отсчет, количество покупателей и т. д.

Чтобы уменьшить вышеупомянутую онлайн-ситуацию, которая не требует онлайн-доступа, разработчики могут добавить имя стиля offline-prerender-tag-nodiff в соответствующий DOM, и OPR не будет сравнивать этот DOM во время процесса сравнения.


7 загрузить cdn

OPR загрузит отображаемую страницу на cdn в соответствии с URL-адресом, например:

Домашняя страница книги Zhuanzhuan: https://m.zhuanzhuan.com/open/ZZBook/index.html#/Book/Home

Он будет загружен на cdn: https://m.zhuanzhuan.com/open/ZZBook/index-Book-Home.html#/Book/Home


Почему бы не index.html, у этого есть несколько преимуществ:


a: отличать адреса OPR от адресов SPA

Нам просто нужно заменить адрес входа на

https://m.zhuanzhuan.com/open/ZZBook/index-Book-Home.html#/Book/Home

Пользователь может получить доступ к странице, отображаемой с помощью OPR. Если пользователь обращается к исходному файлу index.html, он получает доступ только к исходной странице SPA, но скорость обработки будет ниже.


б: снизить риск

Только представьте, если мы запишем файл как index.html, если пользователь впервые зайдет на маршрут /Book/Mine, то пользователь будет очень странным, я захожу на страницу личного центра, зачем вы хотите мне показать сначала домашняя страница? .

В то же время это также предотвращает риск того, что все страницы будут недоступны из-за аварии в службе OPR.


Вторичный рендеринг

Как упоминалось выше, когда пользователь получает доступ к странице, отображаемой с помощью SSR, и странице, отображаемой с помощью OPR, происходит два отображения:

  1. Браузер отображает DOM в HTML (мы называем это первым рендерингом, обратите внимание, что страница в это время статична и с ней нельзя взаимодействовать)

  2. Vue также будет перерисовывать и поддерживать виртуальный DOM и один раз смешивать виртуальный DOM и DOM в HTML (поскольку эти два DOM совершенно одинаковы, вы вообще не видите изменений, но можете взаимодействовать, мы вызываем это второстепенно для короткого рендеринга)

Должен быть вторичный рендеринг, почему?

Поскольку первый рендеринг — это только отображение на уровне DOM, мы должны поместить общую логику Vue в DOM, иначе не будет никаких событий и пользователи не смогут взаимодействовать.

Первый процесс рендеринга SSR и OPR одинаков, но второй рендеринг сильно отличается:


ССР:

Сначала он получит данные из html, а затем выполнит рендеринг и монтирование $mount.Здесь код Vue настраивает специальный процесс для SSR: он попытается смешать его с DOM на странице.Если он полностью непротиворечив, DOM будет повторно использоваться напрямую, и виртуальный DOM будет повторно использован.


ОПР:

Вторичный рендеринг проекта OPR не так прост, как предполагалось, и ему сложно повторно использовать DOM, главным образом потому, что:


Страницам OPR трудно полностью соответствовать DOM.


Поскольку проект SSR получает все данные для однократного рендеринга, время генерации HTML на стороне сервера и время вторичного рендеринга на стороне пользователя точно такое же, и данные также одинаковы, поэтому точно такие же DOM может быть отображен.Если есть какая-либо разница между виртуальным DOM и DOM на странице, Vue удалит существующий DOM страницы и будет использовать новый DOM.


Страницы SPA будут иметь постепенный процесс использования и рендеринга, например:


Рендеринг на странице OPR или SPA выполняется несколько раз:

1. Когда ready=true, сначала завершите первый рендеринг и одновременно начните рендеринг компонента goodsList.

2. Список товаров вызовет второй рендеринг

Если DOM не соответствует странице при ее первом отображении, старый DOM сразу отбрасывается.


Что, если бы мы могли написать более простую структуру для приведенной выше страницы?Например, все компоненты расположены плоско, без контроля v-if, все данные используют кешированные данные, а синхронные данные чтения не могут включать асинхронные процессы, поэтому теоретически они могут быть завершенными. повторное использование DOM в реальности невозможно.Логика в бизнесе гораздо более ответственная, чем предполагалось.Конечно, мы не хотим, чтобы бизнес подвергался большим преобразованиям, что идет вразрез с первоначальным замыслом OPR.


Таким образом, решение вторичного рендеринга, выбранное схемой OPR, таково:Задержка монтирования DOM


Суть этого решения заключается в том, что пока вы не передадите параметр el в процессе нового Vue, Vue завершит рендеринг и построение виртуального DOM в DOM, который не смонтирован на странице, поэтому мы только нужно сделать это в подходящее время.Просто повесить DOM на страницу, какое подходящее время?


Страничный DOM и виртуальный DOM близки к одному и тому же


Сначала поговорим о процессе «монтажа»:Короче говоря, удалите DOM в HTML, а затем вставьте дескриптор виртуального DOM window.vm.$el в тело..


Вы можете беспокоиться о потере производительности, на самом деле процесс удаления и вставки DOM очень быстрый и потребляет очень мало ресурсов для процесса браузера.


Возвращаясь к времени монтирования, что произойдет, если разница страниц слишком велика? Затем пользователь почувствует мерцание страницы, потому что во внешнем виде есть некоторые несоответствия, это должно быть легче понять, поэтому нам нужно выполнить операцию монтирования, когда две DOM почти согласованы.


Задержка времени монтирования



Чтобы узнать, когда два DOM близки к одному и тому же, мы обращаемся к схеме расчета конца первого экрана в схеме статистики производительности Taobao:


Мы используем MutationObserver для отслеживания изменений виртуального DOM и рассчитываем оценку DOM для каждого изменения.Когда оценка DOM близка к существующей оценке DOM страницы, мы монтируем DOM.


Конкретная логика немного сложнее:


Когда два DOM почти идентичны, а затем монтируется DOM, пользователь едва ли почувствует мерцание страницы.

Также см. выше, если используется механизм кэширования интерфейса, это сократит время достижения согласованности DOM.


Другие оптимизации


Чтобы еще больше повысить скорость первого экрана, мы также внесли некоторые оптимизации в решение OPR:

1 CSS tree-shaking

В HTML, который мы сканируем, будет много тегов стиля, можно почти считать, что сколько тегов стилей вы написали в vue, столько же тегов в голове, например:

В этих тегах много повторяющихся стилей.Если ввести HTML, размер файла будет увеличен.Мы провели для этого встряску деревьев.Можно сказать, что исходные 5000+ строк кода CSS можно сократить до 1000+, объяснено в последующих статьях.


2 Измените скрипт на режим асинхронной загрузки

Перед этим вам может понадобиться понять разницу между обычным скриптом, отложенным и асинхронным.

вкратце,

  • Обычный скрипт: загружать и выполнять в порядке записи, препятствовать рендерингу DOM, замедлять время DOMContentLoaded

  • скрипт defer: параллельная загрузка, выполняемая в порядке записи, не мешает рендерингу DOM, тормозит время DOMContentLoaded

  • асинхронный скрипт: параллельная загрузка, тот, кто загрузит первым, будет выполняться первым, не мешает рендерингу DOM, не мешает DOMContentLoaded time

Почему мы используем асинхронность? В младших версиях ядра iOS оно будет ждать, пока страница DOMContentLoaded начнет рендеринг страницы. Если используется обычный скрипт или режим отсрочки, время рендеринга страницы будет отложено.


3 Стратегия понижения рейтинга

Если возникнут какие-либо проблемы, чтобы обеспечить доступность для пользователей, мы составим план перехода на более раннюю версию, который также очень прост:

Захват текстового содержимого самого HTML и синхронизация его с cdn эквивалентны возвращению режима OPR в SPA, у этой стратегии будут соответствующие методы обнаружения и механизмы автоматического переключения в схеме OPR.


Эффект

Решение OPR было подключено ко многим предприятиям нашей компании, и исходный первый экран можно разместить на странице SPA 1500–4000 мс.До 300 мс - 800 мс, можно сказать, что эффект замечательный ~


Последнее примечание

Решение OPR в настоящее время применяется в различных сферах нашей деятельности.Логин не требуетсяНа следующем этапе мы решим рендеринг страницы, который зависит от состояния входа в систему. Читатели могут общаться с нашей компанией.


об авторе



Чжан Суён

Лицо, отвечающее за операционный центр платформы Zhuanzhuan, проводит глубокие исследования в области внешнего интерфейса, в том числе: резка карты одним щелчком мыши, моделирование внешних данных, наращивание базовых возможностей небольших программ и т. д. Из 10 лет опыта работы 2 года был инженером, 5 лет генеральным директором, 3 года техническим менеджером, может написать несколько статей, а также является отличным автором самородков в 2018 году.


Сканировать QR-кодПодписывайтесь на нас