Оптимизация производительности веб-сайта является необходимым навыком и требует длительного накопления.Ниже приведены некоторые стратегии оптимизации производительности, которые я обобщил, в основном разделенные на несколько аспектов:
- Оптимизация сетевых запросов
- оптимизация рендеринга страницы
- JS блокирует производительность и утечки памяти
- Балансировка нагрузки
1 Оптимизация сетевых запросов
1.1 Кэш браузера
Прежде чем браузер инициирует запрос к серверу, он сначала запросит, есть ли тот же файл локально. играют роль промежуточной буферизации. , давайте сначала посмотрим на стратегию браузера по обработке кэширования:
Кэш браузера по умолчанию помещается в память, кеш в памяти будет очищаться при завершении процесса или закрытии браузера, а кеш на жестком диске может сохраняться длительное время. Много раз мы будем видеть два разных состояния в элементе размера каждого запроса в сетевой панели: из кеша памяти и из кеша диска, первое означает, что кеш поступает из памяти, а второе означает, что кеш поступает из жесткого диска. диск. Это не что иное, как поле Etag, которое мы устанавливаем на сервере, которое управляет местом хранения кеша. После того, как браузер получит ответ сервера, он обнаружит заголовок ответа (Header), и при наличии поля Etag браузер запишет этот кеш на жесткий диск.
Возьмите Nginx в качестве примера, установите Etag
etag on; //开启etag验证
expires 14d; //设置缓存过期时间为14天
Откройте наш веб-сайт и наблюдайте за нашими ресурсами запроса в сетевой панели chrome devtools.Если вы видите поля Etag и Expires в заголовке ответа, это означает, что наша конфигурация кеша прошла успешно.
Когда мы настраиваем кеш, мы должны помнить, что если браузер попадет в сильный кеш при обработке пользовательских запросов, браузер будет напрямую извлекать локальный кеш без какой-либо связи с сервером.То есть, если мы обновляем на стороне сервера файл, который неизвестно браузеру, не может заменить недопустимый кеш. Поэтому на этапе построения нам нужно добавить суффикс хеша md5 к нашим статическим ресурсам, чтобы избежать проблемы, связанной с тем, что интерфейсные и внутренние файлы не могут быть синхронизированы из-за обновления ресурсов.
1.2 Упаковка и сжатие ресурсов
Работа по кэшированию браузера, которую мы выполняли ранее, может быть эффективной только тогда, когда пользователь посещает нашу страницу во второй раз.Если мы хотим добиться хорошей производительности, когда пользователь открывает страницу в первый раз, мы должны оптимизировать ресурсы. Мы часто объединяем меры по оптимизации производительности сети в три основных аспекта: сокращение количества запросов, уменьшение объема запрашиваемых ресурсов и увеличение скорости передачи по сети. Теперь давайте разберем его по одному:
Возьмите Webpack в качестве примера
- Сжать JS
new webpack.optimize.UglifyJsPlugin()
- Сжать HTML
new HtmlWebpackPlugin({
template: __dirname + '/views/index.html', // new 一个这个插件的实例,并传入相关的参数
filename: '../index.html',
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
chunksSortMode: 'dependency'
})
Когда мы используем html-webpack-plugin для автоматического внедрения JS и CSS для упаковки HTML-файлов, мы редко добавляем в него элементы конфигурации.Здесь я привожу пример, и вы можете просто скопировать его напрямую.
PS: Вот хитрость: когда мы пишем атрибут src или href HTML-элементов, мы можем опустить часть протокола, что также может сэкономить ресурсы.
- Сжать CSS
В процессе использования вебпака мы обычно вводим css файлы в виде модулей (идея вебпака в том, что все является модулем), но когда мы выходим в интернет, нам тоже нужно извлекать и сжимать эти css файлы. сложный процесс требует всего несколько простых строк конфигурации
const ExtractTextPlugin = require('extract-text-webpack-plugin')
module: {
rules: [..., {
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: {
loader: 'css-loader',
options: {
minimize: true
}
}
})
}]
}
- Использование новой функции webpack3: ModuleConcatenationPlugin
new webpack.optimize.ModuleConcatenationPlugin()
- Установите для параметра shouldUseSourceMap среды prod значение false и удалите файл карты, сгенерированный сборкой.
devtool: shouldUseSourceMap ? 'source-map' : false,
Наконец, мы также должны включить сжатие передачи Gzip на сервере. Он может сжимать наши текстовые файлы до четверти исходного размера, и эффект будет немедленным. Переключитесь на наш файл конфигурации nginx и добавьте следующие два элемента конфигурации:
gzip on;
gzip_types text/plain application/javascriptapplication/x-javascripttext/css application/xml text/javascriptapplication/x-httpd-php application/vnd.ms-fontobject font/ttf font/opentype font/x-woff image/svg+xml;
Если вы видите такое поле в заголовке ответа на запрос веб-сайта, это означает, что наша конфигурация сжатия Gzip прошла успешно:
【! ! ! обращать внимание! ! ! 】Не архивируйте файлы изображений! Не сжимайте файлы изображений! Не сжимайте файлы изображений! Скажу только, что эффект контрпродуктивен.Что касается конкретной причины, то в процессе сжатия нужно учитывать загрузку процессора и степень сжатия сервера.Сжатие изображений не только будет занимать много ресурсов в фоновом режиме, но и эффект сжатия на самом деле не впечатляет.Можно сказать, что «вред перевешивает пользу», поэтому, пожалуйста, удалите соответствующий элемент изображения в gzip_types. Что касается соответствующей обработки изображений, мы представим ее более подробно далее.
1.3 Оптимизация ресурсов изображения
- Не масштабировать изображения в HTML
- Использование спрайтов (CSS Sprite)
- Использование значков шрифтов (iconfont)
1.4 Использование CDN
Используйте CDN для хранения статических ресурсов, избегайте резкого увеличения пропускной способности и ускоряйте загрузку ресурсов.
Оптимизация производительности рендеринга 2 страниц
2.1 Уменьшите количество перерисовок и перекомпоновок
- Разделение чтения и записи свойства CSS: каждый раз, когда браузер считывает стиль элемента, он должен перерисовывать (перекомпоновывать + перерисовывать), поэтому, когда мы используем JS для чтения и записи стиля элемента, лучше всего комбинировать два отдельных, читаемых сначала, а затем напишите, чтобы избежать ситуации перекрестного использования двух. Самое объективное решение — манипулировать стилями элементов без JS, что я и рекомендую больше всего.
- Пакетное управление стилями элементов путем переключения классов или использования свойства элемента style.csstext.
- Автономное обновление элемента DOM: при выполнении связанных операций с DOM, например, appendChild и т. д., можно использовать объект Document Fragment для выполнения автономных операций, снова вставить страницу после «сборки» элемента или использовать display:none. чтобы скрыть элемент, в элементе Выполните соответствующие операции после «исчезновения».
- Сделайте бесполезные элементы невидимыми: видимость: скрытая, это может снизить нагрузку на перерисовку и отображать элементы при необходимости.
- Сжимайте глубину DOM, не используйте слишком глубокие подэлементы в слое рендеринга, используйте меньше DOM для завершения стилей страницы и вместо этого используйте псевдоэлементы или box-shadow.
- Укажите размер изображения перед рендерингом: Поскольку элемент img является встроенным элементом, ширина и высота будут изменены после загрузки изображения. В тяжелых случаях будет перекомпонована вся страница, поэтому лучше указать ее размер до рендеринг, или пусть он не мешает потоку документов.
- Запустите слой рендеринга отдельно для элементов на странице, которая может быть переставлена и переставлена и использовать графический процессор, чтобы поделиться давлением CPU. (Эта стратегия должна использоваться с осторожностью, и важно рассмотреть вопрос о том, можно ли ожидать оптимизации производительности за счет проживания ГПУ. В конце концов, слишком много слоев рендеринга на странице также является ненужным давлением для GPU. Обычно не нужно В этом случае мы ускоряем анимированные элементы.)
2.2 Уменьшить повторный рендеринг страницы и вложенность Dom
- Возьмем React в качестве примера, если это приведет к изменению состояния страницы, лучше всего обработать его в shouldComponentUpdate, чтобы избежать повторного рендеринга каждый раз, когда обновляются реквизиты или состояние.Если страница в основном используется для отображения, вы можете используйте PureComponent вместо Component.Изменяется тип ссылки, без повторного рендеринга. Разумно используйте Фрагмент вместо Компонента, чтобы уменьшить вложенность Домов.
3 JS блокирует производительность и утечку памяти
3.1 Использование JS-анти-шейка и троттлинга
Функция anti-shake: объединить несколько операций в одну операцию. Принцип заключается в поддержании таймера, который предусматривает, что функция срабатывает после времени задержки, но если она снова срабатывает в течение времени задержки, предыдущий таймер будет отменен и сброшен. Таким образом, может быть запущено только последнее действие.
function debounce(fn, wait) {
var timeout = null;
return function() {
if(timeout !== null)
clearTimeout(timeout);
timeout = setTimeout(fn, wait);
}
}
Функция дроссера: сделать только функцию в течение определенного периода времени. Принцип состоит в том, чтобы вызвать функцию путем оценки того, достичь определенного периода времени.
var throttle = function(func, delay) {
var prev = Date.now();
return function() {
var context = this;
var args = arguments;
var now = Date.now();
if (now - prev >= delay) {
func.apply(context, args);
prev = Date.now();
}
}
}
Отличие: регулирование функций гарантирует, что реальная функция обработки событий будет выполняться в течение заданного времени, независимо от того, как часто событие запускается, в то время как функция защиты от сотрясений запускает функцию только один раз после последнего события. Например, в сценарии с бесконечной загрузкой страницы нам нужно, чтобы пользователь время от времени отправлял Ajax-запрос во время прокрутки страницы, а не запрашивал данные, когда пользователь переставал прокручивать страницу. Такой сценарий подходит для достижения технологии дросселирования.
3.2 Утечки памяти
- Паттерн утечки памяти при закрытии
- Когда страница (SPA) WillUnMount, не забудьте закрыть некоторые ресурсы, такие как отключение WebSocket, пустой объект eChart и т. д.
4 Балансировка нагрузки
- Управляйте несколькими процессами с помощью PM2
- Nginx как обратный прокси
- Docker управляет несколькими контейнерами