Эта статья была опубликована сообществом cloud+community
Автор: Сиян Джакс
В мире боевых искусств только (вэй) быстро (фу), но не (бу) ломается (по).
В связи с быстрым развитием фронтенд-технологий в последние годы все больше и больше команд используют фреймворки SPA, такие как React и Vue, в качестве основного технологического стека. Взяв в качестве примера приложение React, с точки зрения производительности наиболее важной метрикой, вероятно, являетсяРендеринг выше сгибавремя потрачено. Итак, сегодня мы хотим поделиться с вами историей о экстремальной оптимизации.
Наша цель - сделатьСтраницы H5 также могут иметь нативный интерфейс., если вы все еще ищете, какие технологии могут сделать боссаТело тигра трясется(Сохраните свои KPI), тогда эта статья может вам помочь.
Что такое страница сведений о курсе обучения пингвинов
Страница сведений о курсе является одной из самых важных страниц приложения для консультирования пингвинов Tencent, поток также является одной из самых больших страниц, поэтому скорость открытия имеет важное значение.
Это использованиеReactНаписана страница H5, работающая на нескольких терминалах, в том числе:企鹅辅导APP,手机 QQ,手机浏览器.
Эволюция архитектуры
Чистый асинхронный рендеринг
Мы знаем, что методы рендеринга по умолчанию для текущих основных приложений SPA выглядят следующим образом:
В этом случае от загрузки страницы до момента, когда пользователь увидит страницу (Рендеринг выше сгибапотраченное время) — это время, обведенное серой рамкой на изображении выше.
Это самый медленный способ, даже если CGI достаточно быстр, стоит минимум1Sприбыть2Sо времени.
Тогда мыПростая оптимизацияодин раз:
- Кэшируйте статические ресурсы, чтобы в следующий раз, когда пользователь откроет их, им не пришлось запрашивать их из сети.
- первый④Можно ли натянуть CGI пошагово заранее? После запроса HTML мы можем сначала запросить данные CGI через скрипт JS, а затем первый④Когда вы делаете шаг, вы можете получить данные напрямую, этоПредварительная загрузка компьютерной графики.
Как это сделать? Наше решение состоит в том, чтобы единообразно инкапсулировать инструмент запроса запроса.При упаковке с помощью Webpack фрагмент кода JS, который предварительно загружает CGI, будет внедрен в верхнюю часть страницы, а MAP, соответствующий CGI и DATA, будет сохранен.При отправке запросов позже , перейдите на MAP, чтобы получить значение, если значение есть, извлеките его напрямую, если нет, инициируйте HTTP-запрос. (Подробности см. в открытом доступе нашей команды.Preloadинструмент)
В этом режиме есть и другие оптимизации:
- Реализовать состояние загрузки или скелетный экран в HTML;
- удалить внешний css;
- Используйте динамические полифиллы;
- Используйте SplitChunksPlugin для разделения общего кода;
- Правильное использование Tree Shaking Webpack 4.0;
- Используйте динамический импорт, чтобы разделить код страницы и уменьшить размер JS в верхней части страницы;
- Скомпилируйте в ES2015+, повысьте эффективность выполнения кода и уменьшите размер;
- Используйте отложенную загрузку и заполнитель, чтобы улучшить процесс загрузки.
Результаты, как показано ниже:
прямой изоморфизм
В асинхронном режиме, помимо вышеперечисленных оптимизаций, мы также сделали in-end (обучающее приложение Penguin, мобильный QQ)Автономный кэш пакетов(Tencent Mobile QQ самостоятельно разработала решение, оптимизированное для мобильных телефонов. Короче говоря, оно кэширует статические ресурсы в мобильных приложениях.) После нашего теста данных первый рендеринг экрана можно открыть за секунды (около 1 с).
Но для нас, кто стремится к максимальной производительности, мы определенно не будем удовлетворены.
продолжить оптимизацию,Самый простой и популярныйРутина определенно должна идти прямо (рендеринг на стороне сервера) вверх.
Сейчас существует много видов прямых решений, и я не буду их здесь представлять.Если вы хотите узнать больше о решениях для рендеринга на стороне сервера, обратитесь к этой статье.
Эффект оптимизации сразу после первого экранного времени очевиден. После нашего теста данные можно улучшить примерно на **25%**.
Эффект после прямого выхода следующий:
Видно, что для первого экрана нет времени ожидания **[Загрузка...]**, и визуальное восприятие значительно улучшилось.
PWA прямо
Что можно оптимизировать для упомянутых выше распространенных приложений? Давайте подробно проанализируем волну, которая также находится в центре внимания того, чем мы хотим поделиться с вами сегодня.
Сначала посмотрите на трудоемкую таблицу каждой ссылки прямой заявки (Местная среда 2018 iMac):
| имя процедуры | стоимость процесса |
|---|---|
| Вытягивание CGI в узле | 300 ms |
| RenderToString | 20 ms |
| сетевое время | 10 ms |
| Внешний HTML-рендеринг | 30 ms |
Из приведенной выше таблицы видно, что трудоемкая часть прямого рендеринга все еще находится в разработке.Вытягивание интерфейса CGIначальство.
Мы сейчас представляемдва вопроса:
- Можно ли кэшировать данные интерфейса CGI?
- Можно ли кэшировать HTML?
Во-первых, динамическое и статическое разделение интерфейса
В данных интерфейса этой страницы есть некоторые данные, которые меняются в режиме реального времени, такие как: сколько мест осталось, цена курса на данный момент, купил ли пользователь курс и т.д.
Характеристики этих данных определяют этоИнтерфейс данных не может быть кэширован. (Предполагая, что он кэширован, будут случаи, когда пользователи могут зайти и увидеть, что на данный момент осталось 10 мест, но курс уже распродан)
Большую часть этого трудоемкого времени мы сделалиДинамическое и статическое разделение интерфейса CGI.
Данные, не связанные с режимом пользователя и текущим временем (например,
课程标题,课程上课的时间,试听模块的地址и т.д.) размещаются в одном интерфейсе (статический интерфейс), а остальные изменяющиеся данные размещаются в другом интерфейсе (динамический интерфейс).
Тогда можно использовать статический интерфейс для рендеринга на стороне сервера, преимущество в том, что первый быстрее (меньше динамической информации, да и фон тоже можно кешировать), а второй Node можно использовать для кеширования напрямую.
2. Прямо из кеша Redis
Таким образом, мы можем использовать ту часть статических данных, которая не меняется часто, для прямого вывода HTML,Затем кэшируйте этот файл HTML в Redis..
Клиент запрашивает эту веб-страницу. После того, как сторона узла получает запрос, она сначала обращается к Redis, чтобы получить кешированный HTML. Если кеш Redis не попадает, он извлекает статический интерфейс CGI, отображает HTML и сохраняет его в Redis.
После того, как клиент получит HTML, он немедленно отобразится, а затем с помощью JS запросит динамические данные и отобразит их в соответствующем месте.
После этого мы видим, что улучшение эффекта оптимизации очень и очень очевидно:
Непосредственно из262msподнят до16ms! (Местная среда), это похоже на полет, и моей маме больше не нужно беспокоиться о лидерах, отнимающих много времени.
3. PWA прямо из кеша
Для получения дополнительной информации о том, что такое PWA и как его использовать, посетите эту статью.
Сделав кеширование HTML прямо со стороны Node, мы продолжили оптимизацию, а потом подумали, можно ли кэшировать HTML на стороне клиента, чтобы подключениеЭта часть потребления сетевой задержки также сохраняетсяШерстяная ткань.
Ответ заключается в использованииPWAВыполняйте автономное кэширование на стороне клиента, кэшируйте наш прямой HTML-код на стороне клиента каждый раз, когда пользователь запрашивает, непосредственно изPWAПолучите соответствующий ответ прямой страницы (HTML) из автономного кэша пользователю, а затем запросите службу Node для обновления локальногоPWAкеш. (Как показано ниже)
Основной код:
self.addEventListener("fetch", event => {
// TODO other logic (maybe fetch filter)
// core logic
event.respondWith(
caches.open(cacheName).then(function(cache) {
return cache.match(cacheCourseUrl).then(function(response) {
var fetchPromise = fetch(cacheCourseUrl).then(function(
networkResponse
) {
if (networkResponse.status === 200) {
cache.put(cacheCourseUrl, networkResponse.clone());
}
return networkResponse;
});
return response || fetchPromise;
});
})
);
});
Без дальнейших церемоний, давайте сначала посмотрим на сравнение эффектов (слева — PWA, справа — автономный пакет):
Как видно из рисунка выше, после использования PWA для прямого выхода из кеша,Первый рендеринг экрана в основном миллисекунды, можно сказать, бок о бок с Native.
После нашего теста данных, используя PWA непосредственно из кеша, лучше всего достигается время рендеринга первого экрана.400msЛевый и правый уровни:
Прямая детальная оптимизация PWA
1. Предотвратите биение страницы
Поскольку интерфейс отделен от статического и динамического, статический интерфейс используется для прямого вывода страницы, а затем динамические данные извлекаются и отображаются на стороне клиента. Это может вызвать дрожание страницы (например, модуль прослушивания на странице сведений, отображаемый на стороне клиента).
Из-за изменения высоты будет наблюдаться визуальное дрожание (подробности см. на снимке экрана в формате GIF выше).
Для устранения перелистывания страниц необходимо убедиться, чтоВысота контейнера уже существует, когда он прямой.
Например, в этом модуле прослушивания фактически изображение обложки и кнопка прослушивания могут отображаться на стороне сервера, а последний модуль «Видео» должен отображаться на стороне клиента (Tencent Cloud Tcplayer).
Таким образом, его можно разделить на: (звуковая обложка + кнопка + время) рендеринг на стороне сервера + основное видео (рендеринг на стороне клиента).
Некоторые контейнеры, которым необходимо вычислять высоту на стороне клиента (которые часто вычисляются в ComponentDidMount), если они зависят от среды клиента (например, в зависимости от того, является ли текущая система Android или IOS),В результате они не должны отображаться непосредственно на стороне сервера., как это сделать?
Что мы делаем здесь, так это помещаем эти вычисления перед телом HTML, встраиваем встроенный скрипт для расчета текущей среды, добавляем определенный класс в тело, а затем добавляем определенный класс к элементу в этом конкретном классе.Конкретные стили могут быть дается через css. Например следующий код:
/*
* 因为在不同的手机 APP 环境内,页面的 padding 是不一样的。
* 我们要在页面渲染完之前加上相应的 padding
*/
var REGEXP_FUDAO_APP = /EducationApp/;
if (
typeof navigator !== "undefined" &&
REGEXP_FUDAO_APP.test(navigator.userAgent)
) {
if (/Android/i.test(navigator.userAgent)) {
document.body.classList.add("androidFudaoApp");
} else if (/iPhone|iPad|iPod|iOS/i.test(navigator.userAgent)) {
if (window.screen.width === 375 && window.screen.height === 812) {
document.body.classList.add("iphoneXFudaoApp");
} else {
document.body.classList.add("iosFudaoApp");
}
}
}
.androidFudaoApp .tt {
padding-top: 48px;
background-position-y: 84px;
}
.iphoneXFudaoApp .tt {
padding-top: 88px;
background-position-y: 124px;
}
.iosFudaoApp .tt {
padding-top: 64px;
background-position-y: 100px;
}
Затем вставьте этот код, построив его перед телом страницы.
Эффект оптимизации защиты от сотрясений выглядит следующим образом (Слева оптимизировано, справа не оптимизировано):
Во-вторых, предварительная нагрузка холодного пуска
Несмотря на то, что мы сделали автономное кэширование PWA, для холодного запуска в клиенте все еще нет кэша PWA, что приведет к тому, что страница будет щелкнута в первый раз, а скорость рендеринга будет относительно низкой.
Здесь мы можем использовать предварительно загруженный скрипт, чтобы получить максимальное количество страниц, которые пользователи могут посетить при запуске приложения.
Основной код выглядит следующим образом:
// 预加载页面时, PWA 预缓存课程详情页面的直出
function prefetchCache(fetchUrl) {
fetch("https://you preFetch Cgi")
.then(data => {
return data.json();
})
.then(res => {
const { courseInfo = [] } = res.result || {};
courseInfo.forEach(item => {
if (item.cid) {
caches.open(cacheName).then(function(cache) {
fetch(`${courseURL}?course_id=${item.cid}`).then(function(
networkResponse
) {
if (networkResponse.status === 200) {
cache.put(
`${courseURL}?course_id=${item.cid}`,
networkResponse.clone()
);
}
// return networkResponse;
});
});
}
});
})
.catch(err => {
// To monitor err
});
}
PWA прямо из устаревших проблем
1. Проблемы совместимости
С развитием технологии PWA большинство мобильных телефонов и ПК теперь поддерживают PWA. После нашего тестирования мы обнаружили, что: Android в основном поддерживается, а IOS должна поддерживаться выше 11.3.
Карта совместимости сервис-воркеров
2. Проблема с рендерингом iOS
Большой опыт подсказывает нам, что тег исходящего скрипта следует размещать после тела, поскольку он будет блокировать рендеринг страницы в формате DOM.
После тестирования выяснилось, что IOSWebView (UIWebView) Механизм рендеринга отличается от описанного выше, но страница не будет рендериться до тех пор, пока не будет выполнен последующий JS.В этом случае наша оптимизация прямого рендеринга не будет иметь никакого эффекта (поскольку HTML не рендерится в момент начало), здесь можно использоватьscriptпомеченasyncа такжеdeferсвойства для достижения эффекта асинхронного рендеринга.
После обновления WkWebView ситуация улучшилась и рендеринг работает нормально.
приложение
использованная литература
- Исследование PWA и лучшие практики
- Передовая изоморфная прямолинейная практика под сотнями миллионов посещений
- Руководство по оптимизации производительности загрузки React 16
Эта статья была разрешена автором для публикации сообщества Tencent Cloud + на различных каналах.
оригинал:Страница сведений о курсе Penguin Tutoring MS Open Secret - PWA Straight Out
Чтобы узнать больше о свежих технических сухих товарах, вы можете подписаться на насСообщество Tencent Cloud Technology — официальный аккаунт сообщества Yunjia и аккаунт Zhihu Institution