После получасовой беседы с интервьюером во время последнего собеседования интервьюер вдруг спросил: Какие оптимизации производительности можно выполнить во внешнем интерфейсе?

Front-end оптимизация, вероятно, может иметь следующие направления:

  • Оптимизация сети
  • Оптимизация рендеринга страницы
  • JS-оптимизация
  • оптимизация изображения
  • оптимизация упаковки веб-пакета
  • Реагировать на оптимизацию
  • Vue-оптимизация

Оптимизация сети

Предварительное разрешение DNS

Атрибут rel тега link устанавливает dns-prefetch для получения IP-адреса, соответствующего доменному имени заранее.

использовать кеш

Уменьшите нагрузку на сервер и быстро получайте данные

Использование CDN (сети доставки контента)

Физическое расстояние пользователя от сервера также влияет на время отклика.

Сеть доставки контента (CDN) — это группа географически рассредоточенных веб-серверов, используемых для более эффективной доставки контента пользователям. Как правило, сервер, выбранный для доставки контента, зависит от расстояния в сети. Например: выберите сервер с наименьшим количеством переходов или самым быстрым временем отклика.

сжатый ответ

Компонент сжатия повышает производительность за счет уменьшения размера пакетов ответов, создаваемых HTTP-запросами, тем самым сокращая время передачи. Начиная с HTTP1.1, веб-клиенты могут идентифицировать поддержку сжатия с помощью заголовка Accept-Encoding в HTTP-запросе (в этом заголовке запроса будет указан ряд методов сжатия)
Если веб-сервер увидит этот заголовок в запросе, он сжимает ответ, используя один из методов, перечисленных клиентом. Веб-сервер сообщает веб-клиенту, какой метод использовать для сжатия через заголовок Content-Encoding в ответе
HTML-документы обычно сжимаются многими веб-сайтами в наши дни, и сжатие скриптов и таблиц стилей также имеет смысл (любой текстовый ответ , включая XML и JSON, теоретически стоит сжимать). Однако изображения и PDF-файлы не следует сжимать, поскольку они уже сжаты.

использовать несколько доменов

Chrome и другие современные браузеры будут ограничивать количество одновременных загрузок для одного и того же доменного имени. Разные браузеры и версии разные. Использование разных доменных имен может максимизировать поток загрузки, но держите его в пределах 2–4 доменных имен, чтобы избежать потери DNS-запросов.

Избегайте того, чтобы src изображения был пустым

Хотя атрибут src представляет собой пустую строку, браузер все равно инициирует HTTP-запрос к серверу:

IE отправляет запрос в каталог, где находится страница; Safari, Chrome, Firefox отправляют запрос на саму страницу; Опера ничего не делает.

Оптимизация рендеринга страницы

Процесс движка рендеринга Webkit:

  • Обработка HTML и построение дерева DOM
  • Работа с CSS Построение дерева правил CSS (CSSOM)
  • DOM Tree и CSSOM Tree синтезируют дерево рендеринга Render Tree.
  • Разметка по дереву рендеринга, расчет позиции каждого узла
  • Вызывать графический процессор для рисования, синтеза слоев и отображения их на экране.

избежать блокировки css

CSS влияет на построение renderTree и будет блокировать отрисовку страницы, поэтому ресурсы CSS должны быть загружены как можно быстрее (поместите CSS в тег head) и как можно быстрее (включите CDN для оптимизации скорости загрузки статических ресурсов)

Уменьшите сложность селекторов css

Браузер читает селектор, следуя принципу чтения с правой стороны селектора на левую.

  • Уменьшите вложенность: не более трех слоев, а накладные расходы на селекторы потомков высоки, используйте с осторожностью.
  • Избегайте использования подстановочных знаков, просто сопоставьте используемые элементы
  • Используйте наследование, чтобы избежать дублирования сопоставления и определения
  • Правильное использование селекторов классов и селекторов идентификаторов

Избегайте использования выражений CSS

css-выражения оцениваются часто.

Избегайте блокировки js

js может модифицировать CSSOM и DOM, поэтому js заблокирует синтаксический анализ и рендеринг страницы и будет ждать загрузки ресурсов css. То есть js возьмет на себя управление движком рендеринга. Поэтому нам нужно добавить отсрочку или асинхронность к ресурсам js, чтобы отложить выполнение скриптов js.

Используйте внешнюю цепочку js и css

Использование внешних файлов в реальном мире обычно приводит к ускорению страниц, потому что JavaScript и CSS могут кэшироваться браузером. В случае встраивания, поскольку HTML-документы обычно не настроены для кэширования, JavaScript и CSS загружаются каждый раз, когда запрашивается HTML-документ. Таким образом, если JavaScript и CSS находятся во внешних файлах, браузер может кэшировать их, и размер HTML-документа будет уменьшен без увеличения количества HTTP-запросов.

Используйте значок шрифта iconfont вместо значка изображения

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

Оптимизация загрузки первого экрана

  • Используйте скелетный экран или анимацию для оптимизации взаимодействия с пользователем.
  • Ресурсы загружаются по запросу, а ресурсы, которые не нужны на главной странице, загружаются лениво.

Уменьшите количество перерисовок и перекомпоновок

  • Добавьте несколько узлов, используя documentFragment: не является частью реального дома, не вызовет перерисовки и перекомпоновки.
  • Используйте translate вместо top, потому что top вызывает перекомпоновку, а translate - нет. Таким образом, перевод сэкономит время макета, чем top
  • Используйте visibility вместо display: none , потому что первое приведет только к перерисовке, а второе вызовет перекомпоновку (изменение макета); непрозрачность вместо видимости, видимость вызовет перерисовку (рисование), а непрозрачность — нет.
  • Измените DOM в автономном режиме, например: сначала задайте DOM для отображения: нет (с перекомпоновкой), затем вы измените его 100 раз, а затем отобразите.
  • Не помещайте значение атрибута узла DOM в цикл как переменную в цикле.
for (let i = 0; i < 1000; i++) {
  // Getting offsetTop will cause a reflow, because it needs to get the correct value
  console.log(document.querySelector('.test').style.offsetTop)
}
  • Старайтесь как можно меньше использовать разметку таблицы. Для макета таблицы каждый раз при изменении макета ячейки вся вкладка будет перекомпоновываться и перерисовываться;
  • Лучше не использовать узлы DOM часто. Лучше всего заранее прописать стиль, которым нужно оперировать, в класс, а потом его нужно модифицировать. Вам нужно изменить его только один раз. Когда вам нужно изменить его, вы можете напрямую изменить className, чтобы обновить несколько атрибутов DOM css одновременно. Стоимость одной перерисовки оплавления намного ниже, чем стоимость нескольких перерисовок оплавления;
  • Выбор скорости анимации, чем быстрее скорость анимации, тем больше время перекомпоновки, вы также можете использовать requestAnimationFrame
  • Каждый раз, когда вы обращаетесь к свойству смещения DOM, такому как scrollTop, scrollLeft, scrollWidth, offsetTop, offsetLeft, offsetWidth, offsetHeight и другим свойствам элемента, браузер будет перекомпоновывать для получения последнего значения, чтобы гарантировать, что значение правильный. Поэтому, если вы хотите работать несколько раз, лучше всего сделать кеш после выборки. Не обращаться к атрибуту DOM offset в цикле for, а при его использовании лучше всего определить переменную, присвоить ей нужное значение, выполнить кэширование значений и уменьшить количество перерисовок reflow;
  • Превратите часто выполняемые анимации в слои, что может предотвратить перекомпоновку узла и влияние на другие элементы. Например, для тега видео браузер автоматически превратит узел в слой.

JS-оптимизация

Используйте делегирование событий

Стабилизация и троттлинг

Старайтесь не использовать анимацию JS

Как анимация css3, так и анимация холста имеют лучшую производительность, чем анимация JS.

Многопоточность

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

Кэш результатов вычислений

Сократите количество операций, например, вычисляемых в vue.

Оптимизация изображения

Спрайт Рисунок

Оптимизируйте, уменьшив количество http-запросов

Ленивая загрузка изображения

Загружать, когда изображение вот-вот войдет в видимую область

Используйте CSS3 вместо изображений

Есть много изображений, которые можно нарисовать с помощью CSS-эффектов (градиентов, теней и т. д.), и в этом случае лучше использовать CSS3.

Сжатие изображения

Существует два метода сжатия: один — сжимать через онлайн-сайт, а другой — использовать плагин image-webpack-loader для веб-пакетов. Он основан на библиотеке imagemin Node для сжатия изображений.

Используйте прогрессивный JPEG

Использование прогрессивного JPEG улучшит взаимодействие с пользователем

Изображения в формате webp

webp — это новый формат файла изображения, который обеспечивает сжатие как с потерями, так и без потерь. При одинаковом качестве изображения webp меньше, чем png и jpg.

Оптимизация упаковки Webpack

Сузить область соответствия загрузчика

  • Оптимизация конфигурации загрузчика
  • Протестируйте, включите и исключите три элемента конфигурации, чтобы сузить область обработки загрузчика.
  • рекомендуется включать
include: path.resolve(__dirname, "./src"),

разрешение.модули

resolve.modules используется для настройки каталогов, в которых webpack ищет сторонние модули, по умолчанию это node_modules.
Чтобы найти третью сторону, по умолчанию нужно найти ее в node_modules в текущем каталоге проекта. Если он не найден, он перейдет в верхний каталог ../node_modules, чтобы найти его, а если он не найден, он перейдет в ../../node_modules, чтобы найти его. По аналогии он очень похож на механизм поиска модулей Node.js.
Если наши сторонние модули установлены в корневую директорию проекта, мы можем напрямую указать этот путь.

module.exports={
 resolve:{
 modules: [path.resolve(__dirname, "./node_modules")]
 }
}

разрешение.расширения

Когда оператор импорта resolve.extensions не имеет суффикса файла, webpack автоматически добавит суффикс, чтобы попытаться выяснить, существует ли файл.

  • Старайтесь, чтобы список попыток суффикса был как можно меньше.
  • Оператор импорта должен иметь как можно больше суффиксов.

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

Извлечь css

С плагином mini-css-extract-plugin: этот плагин извлекает CSS в отдельные файлы, создает файл CSS для каждого файла JS, содержащего CSS, и поддерживает загрузку CSS и SourceMaps по запросу.

const MiniCssExtractPlugin = require("mini-css-extract-plugin");
 {
 test: /\.less$/,
 use: [
 // "style-loader", //No need for style-loader, use MiniCssExtractPlugin.loader instead
  MiniCssExtractPlugin.loader,
  "css-loader", // compile css
  "postcss-loader",
  "less-loader" // compile less
 ]
 },
plugins: [
  new MiniCssExtractPlugin({
   filename: "css/[name]_[contenthash:6].css",
   chunkFilename: "[id].css"
  })
 ]

сжатие кода

Сжатие кода JS

режим: производственный, с использованием terser-webpack-plugin

module.exports = {
    // ...
    optimization: {
        minimize: true,
        minimizer: [
            new TerserPlugin({}),
        ]
    }
}

Сжатие кода CSS

css-минимизатор-webpack-плагин

module.exports = {
    // ...
    optimization: {
        minimize: true,
        minimizer: [
            new CssMinimizerPlugin({})
        ]
    }
}

Сжатие кода HTML-файла

module.exports = {
    ...
    plugin:[
        new HtmlwebpackPlugin({
            ...
            minify:{
                minifyCSS:false, // whether to compress css
                collapseWhitespace:false, // Whether to fold spaces
                removeComments:true // Whether to remove comments
            }
        })
    ]
}

Если установлено значение minify, фактически будет использоваться другой плагин html-minifier-terser.

Сжатие размера файла

Сжимайте размер файла, чтобы уменьшить потери широкополосного доступа при передаче по протоколу HTTP.

npm install compression-webpack-plugin -D
new ComepressionPlugin({
    test:/.(css|js)$/,  // Which files need to be compressed
    threshold:500, // Set the size of the file to start compressing
    minRatio:0.7, // at least the ratio of compression
    algorithm:"gzip", // The compression algorithm used
})

Сжатие изображения

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

Метод настройки следующий:

module: {
  rules: [
    {
      test: /.(png|jpg|gif)$/,
      use: [
        {
          loader: 'file-loader',
          options: {
            name: '[name]_[hash].[ext]',
            outputPath: 'images/',
          }
        },
        {
          loader: 'image-webpack-loader',
          options: {
            // Configuration for compressing jpeg
            mozjpeg: {
              progressive: true,
              quality: 65
            },
            // Use imagemin**-optipng to compress png, enable: false is off
            optipng: {
              enabled: false,
            },
            // Compress pngs with imagemin-pngquant
            pngquant: {
              quality: '65-90',
              speed: 4
            },
            // Configuration for compressing gif
            gifsicle: {
              interlaced: false,
            },
            // When webp is enabled, jpg and png images will be compressed into webp format
            webp: {
              quality: 75
            }
          }
        }
      ]
    },
  ]
} 

Встряхивание дерева удаляет мертвый код

Tree Shaking — это термин, который означает устранение мертвого кода на компьютерах, опираясь на статический синтаксический анализ модуля ES (без выполнения какого-либо кода вы можете четко знать зависимости модулей).

Существует два разных решения для реализации встряхивания дерева в веб-пакете:

  • usedExports: отмечая, используются ли определенные функции, а затем оптимизируя их через Terser
  • sideEffects: пропустить весь модуль/файл и напрямую проверить, есть ли у файла побочные эффекты.

Две разные схемы конфигурации имеют разные эффекты

используемые экспорты

Метод настройки также очень прост, просто установите для параметра usedExports значение true.

module.exports = {
    ...
    optimization:{
        usedExports
    }
}

После использования неиспользуемый код будет добавлен в комментарий unused Harmony Export mul в пакете webpack, чтобы сообщить Терсеру, что этот код может быть удален во время оптимизации.

побочные эффекты

sideEffects используется, чтобы сообщить компилятору веб-пакета, какие модули имеют побочные эффекты. Метод настройки заключается в установке свойства sideEffects в package.json
Если для параметра sideEffects задано значение false, он сообщает веб-пакету, что может безопасно удалить неиспользуемые экспорты
Если необходимо сохранить некоторые файлы, их можно установить в виде массива

"sideEffecis":[
    "./src/util/format.js",
    "*.css" // all css files
]

Все вышеперечисленное касается встряхивания дерева javascript, css также может реализовать встряхивание дерева.

css встряхивание дерева

css для оптимизации встряхивания дерева можно установить плагин PurgeCss

npm install purgecss-plugin-webpack -D
const PurgeCssPlugin = require('purgecss-webpack-plugin')
module.exports = {
    ...
    plugins:[
        new PurgeCssPlugin({
            path:glob.sync(`${path.resolve('./src')}/**/*`), {nodir:true}// All files in src
            satelist:function(){
                return {
                    standard:["html"]
                }
            }
        })
    ]
}
  • paths: указывает, какие каталоги необходимо проанализировать, чтобы обнаружить содержимое, и использовать glob вместе.
  • По умолчанию Purgecss удалит стиль наших html-тегов, если мы хотим сохранить его, мы можем добавить атрибут списка надежных отправителей.

Babel-plugin-transform-runtime уменьшает избыточность преобразования ES6 ES5

Плагин Babel вводит некоторые вспомогательные функции при преобразовании кода ES6 в код ES5. По умолчанию Babel встраивает коды зависимых вспомогательных функций в каждый выходной файл. Если от этих вспомогательных функций зависит несколько файлов исходного кода, код этих вспомогательных функций будет появляться много раз, что приводит к избыточности кода. Чтобы код этих вспомогательных функций не появлялся повторно, их можно импортировать с помощью require(‘babel-runtime/helpers/createClass’) при их использовании, чтобы они появлялись только один раз. Плагин babel-plugin-transform-runtime используется для реализации этой функции, заменяя связанные вспомогательные функции операторами импорта, тем самым уменьшая размер файла кода, скомпилированного babel.

разделение кода

Разделите код на разные пакеты, и тогда мы сможем загружать эти файлы по требованию или загружать эти файлы параллельно
По умолчанию все коды JavaScript (бизнес-коды, сторонние зависимости и временно неиспользуемые модули) загружаются на главная страница, что повлияет на скорость загрузки главной страницы
Разделение кода может разделять небольшие пакеты и управлять приоритетом загрузки ресурсов для повышения производительности загрузки кода
Это достигается с помощью splitChunksPlugin, веб-пакет плагина был установлен и интегрирован по умолчанию, и его нужно только настроить
В конфигурации по умолчанию чанки предназначены только для асинхронных (асинхронных) запросов, мы можем установить его на начальный или все

module.exports = {
    ...
    optimization:{
        splitChunks:{
            chunks:"all"
        }
    }
}

Основные атрибуты splitChunks следующие:

  • Чанки: обрабатывать ли синхронный код или асинхронный код
  • minSize: размер разделенного пакета, не менее minSize, если размер пакета не превышает minSize, этот пакет не будет разделен
  • maxSize: разбить пакеты размером больше maxSize на пакеты не меньше minSize.
  • minChunks: количество введений, по умолчанию 1

Многопоточная упаковка повышает скорость упаковки

вью

  1. v-для добавления ключа
  2. Маршрутизация ленивой загрузки
  3. Импорт сторонних плагинов по запросу
  4. Разумное использование вычислений и часов
  5. Избегайте использования v-if, когда v-for
  6. Уничтожать события во время удаления: такие как события, добавленные addEventListener, setTimeout, setInterval, bus.$on связанные события прослушивания и т. д.

Реагировать

  1. Цикл карты показывает добавление ключа
  2. Маршрутизация ленивой загрузки
  3. Импорт сторонних плагинов по запросу
  4. Используйте scu, memo или pureComponent, чтобы избежать ненужного рендеринга.
  5. Разумное использование useMemo, memo, useCallback

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

  • useCallback: «запоминается» для функции. Когда его зависимости не изменились, ссылка на функцию не будет переназначена при обновлении компонента. Когда мы чувствуем, что функции не нужно обновлять ссылочный адрес при обновлении компонента, мы можем использовать useCallback для его изменения.
  • React.memo: «запоминает» компонент. Когда реквизиты, которые он получает, не изменились, он вернет результат последнего рендеринга и не будет повторно выполнять функцию, чтобы вернуть новый результат рендеринга.
  • React.useMemo: своего рода «память» для вычисления значения. Когда зависимости не изменились, то нет необходимости вычислять заново, и используется непосредственно предыдущее значение. Для компонентов одним из преимуществ этого является то, что он может сократить некоторые вычисления, чтобы избежать избыточного рендеринга. Когда мы сталкиваемся с некоторыми данными, которые необходимо вычислить внутри компонента, мы можем рассмотреть React.useMemo

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





Дополнительные материалы на PlainEnglish.io.

Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter, LinkedIn, YouTube и Discord .

Заинтересованы в масштабировании запуска вашего программного обеспечения? Ознакомьтесь с разделом Схема.