🚀 Помните об оптимизации производительности интерфейса

внешний интерфейс оптимизация производительности

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

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

используется в проектеWebpackВерсия 3.x, а оптимизированное решение по-прежнему основано на версии Webpack 3.x.VueЛеса оптимизированы. Планируется обновление до 4.x. . .

Обобщил один раз передПрименение Webpack 2.x в проекте Vue2.x,упомянулWebpackНекоторые схемы оптимизации проекта, ниже в качестве дополнения.

Включить сжатие

Я попытался включить gzip, и прямая выгода все еще относительно велика. Ниже приведен результат упаковки в реальном проекте.

  • Parsedjs, 1,38 млн.

parsed-js

  • Gizppedjs — 421,46 КБ

gzipped-js

Webpack__Gzipped_

Благодаря анализу данных объем упаковки сократился на **70,28%**.

Чтобы открыть метод, измените файл конфигурации в скаффолдинге:/config/index.js

// 生产模式
build: {
  productionGzip: true // 开启Gzip压缩
}

При этом серверnginxДобавить элемент конфигурации

gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_comp_level 6;
gzip_types application/javascript text/plain application/x-javascript text/css application/xml text/javascript application/json;
gzip_vary on;

перезагружатьnginxПосле обновления страницы вChrome develop toolsсерединаNetworkПосмотреть веб-ссылку

Request Headersпоявляться вAccept-Encoding: gzipОт имени клиента можно понятьgzipкодирование сжатия

gzip_network

Response Headersпоявляться вContent-EncodingОт имени сервера укажитеgzipКодирование для сжатия данных

gzip_network

Эта пара ключевых слов заголовка запроса отображается вместе, указывая на то, что конфигурация выполнена успешно.

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

preload-webpack-plugin

💡 ИспользуйтеResource Hintsсерединаpreloadиprefetchдля повышения производительности приложений.

оpreloadиprefetch

<link rel="preload">Это подсказка ресурса, которая используется для указания ресурсов, которые будут использоваться вскоре после загрузки страницы, поэтому в процессе загрузки страницы мы хотим выполнить предварительную загрузку как можно скорее, прежде чем браузер начнет отображать основное тело.

<link rel="prefetch">Это подсказка ресурса, которая говорит браузеру использовать время простоя для получения контента, который пользователь может посетить в будущем после загрузки страницы.

Настроить предварительную загрузку в Webpack

preload-webpack-pluginдаhtml-webpack-pluginРасширение плагина, поэтому его нужно использовать вместе.

например конфигурацияpreload:

plugins: [
  new HtmlWebpackPlugin(),
  new PreloadWebpackPlugin({
    rel: 'preload',
    as(entry) {
      if (/\.css$/.test(entry)) return 'style';
      if (/\.woff$/.test(entry)) return 'font';
      if (/\.png$/.test(entry)) return 'image';
      return 'script';
    },
    include: ['app']
  })
]

Последняя инъекция в html:

<link rel="preload" as="script" href="app.31132ae6680e598f8879.js">

Настроить предварительную выборку в Webpack

prefetchСовместимость с ВьюОтложенная загрузка маршрутаРазделение кода лучше

Поскольку маршрутизация не используется в инструменте визуализации этого проекта, конфигурация отсутствует.prefetch.

оптимизировать пакет

В настоящее время в проекте обычно используются библиотеки классов инструментов: lodash, moment, element-ui.Для этих часто используемых библиотек классов вы можете использоватьDllpluginРазделите зависимости в статический репозиторий. Обычно эта версия пакета зависимостей не изменяется.

Однако, как и у lodash и moment, есть и другие способы уменьшить размер упаковки.

  • нагрузка по требованиюelement-ui, см. официальную документацию

  • нагрузка по требованиюlodash

Как правило, когда мы используем lodash, мы не будем использовать все его функции. Можно использовать несколько.В настоящее время вы можете импортировать lodash по запросу, а не в полном объеме. Установив два плагина ниже:

npm i babel-plugin-lodash lodash-webpack-plugin -D

настроить.babelrcдокумент

"plugins": [
  "lodash"
]
  • использоватьdayjsзаменятьmoment, API в основном такой же, после использования вы обнаружите, что можно использовать большинство сценариев, а упаковка только7KB.

Обновите HTTP2

Компонентов в инструменте визуализации становится все больше и больше, и результирующий интерфейс данных запроса страницы постепенно увеличивается, а накладные расходы постепенно увеличиваются. Одностраничный запрос интерфейса данных варьируется от десятков до сотен.

Если вы продолжаете использовать HTTP1.x, все понимают ограничения протокола HTTP1.x.Большинство современных браузеров поддерживают максимальное количество 6 запросов от хоста одновременно, то есть если эти 6 интерфейсных запросов не возвращают результатов вpendingЕсли он находится в состоянии, страница не сможет постоянно обновлять данные, поэтому пользовательский опыт будет очень плохим. Мультиплексирование HTTP2 решает эту проблему, мы обновляем сервер доHTTP2Увеличивает пропускную способность соединения запросов браузера и значительно повышает производительность приложений.

Введение в HTTP2

Http2.0 может сделать наши приложения быстрее, проще и крепче --- «Окончательное руководство по веб-характеристикам»

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

Ядром улучшений производительности HTTP 2.0 является новый二进制分帧层, который определяет, как HTTP-сообщения инкапсулируются и передаются между клиентом и сервером.

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

HTTP 2.0二进制分帧Этот механизм решает проблему блокировки очереди в HTTP 1.x, а также устраняет необходимость в нескольких соединениях для параллельной обработки и отправки запросов и ответов. Результатом являются более быстрые приложения, более простая разработка и более низкие затраты на развертывание.

Оптимизация HTTP2

  • 域名分区Антипаттерн в HTTP 2.0, поскольку множественные соединения сводят на нет эффективность сжатия заголовков и приоритизации запросов в новом протоколе.
  • Удалите ненужную упаковку ресурсов, такую ​​как создание изображений спрайтов, поддержите HTTP 2.0, и многие небольшие ресурсы могут быть отправлены параллельно, что приведет к снижению эффективности ресурсов упаковки.
  • Используйте кэширование на стороне клиента для ресурсов приложения
  • Разверните HTTP 2.0 и разверните протокол TLS (безопасность транспортного уровня), который является HTTPS.

Использовать HTTP-кеш

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

Cache-Control

Общие поля заголовка заголовка HTTP-запроса, просто укажите явное время кэширования. можно настроить вnginxв файле конфигурации.

location ~ .*\.(js|css|ttf|svg|ico){
    add_header Cache-Control  max-age=86400;
}

Страница загружается в первый раз

缓存前

загрузить снова

缓存后

проверка кеша

缓存验证

Вы можете видеть, что после добавления кеша,Status Code200 ОК (из кеша памяти), а время кеша:max-age=86400

Компоненты пакетного рендеринга Vue

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

  • Обход всех компонентов и визуализация компонентов, когда каждый запрос интерфейса возвращает данные
  • Запрашивать все интерфейсы и пакетно отображать компоненты, когда возвращаются все данные

Практикой установлено, что последний рендерится быстрее, а второй исключает время на рендеринг компонента после каждого запроса к интерфейсу, т.к. многократный рендеринг компонента будет приносить дополнительныеScriptingнакладные расходы, как в Vuecomputedилиwatch; В то же время, в сочетании с мультиплексированием HTTP2, запросы для нескольких интерфейсов также будут отвечать быстро.

Образец кода:

// 批量更新组件方法
batchUpdateComponent({ dispatch }, promises) {
  // 请求所有接口
  return Promise.all(promises.map(p => p.catch(() => undefined)))
    .catch(err => {
      console.log(err)
    })
    .then(res => {
      // 一次性渲染组件
      res && dispatch('updateComponent', res)
    })
}

💡 Если обратный вызов catch промиса возвращает неопределенное значение, то сбой промиса будет считаться успешным. использоватьES2018предложениеPromise.finally

Асинхронные компоненты Vue

Объем бизнес-кода приложения в проекте постоянно увеличивается, и написано много бизнес-компонентов, ведь в определенных сценариях не все компоненты нужно рендерить, например, визуализация имеет режим редактирования и режим предварительного просмотра. Необходимо использовать режим редактированияCode Mirrorнаписать немногоSQLзаявление, вам не нужно использовать его в режиме предварительного просмотра.

Компоненты импортируются нормально:

import CustomSql from '@/components/CustomSql'

export default {
  components: {
    CustomSql
  }
}

Компоненты вводятся асинхронно:

// ES6 结合 Webpack 
export default {
  components: {
    CustomSql: () => import('./CustomSql')
  }
}

Маршрутизация ленивой загрузки в Vue заключается в использованииАсинхронные компонентыиWebpackизразделение кодаосуществленный.

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

По мере увеличения количества компонентов в проекте значки компонентов также становятся более многочисленными. Большинство иконок в формате svg, мы можем использоватьSVG SpriteУправление технологиями SVG Icon.

Технология спрайтов SVG

так называемыйSVG SpriteАналогично в CSSSpriteТехнологии. Объедините значки вместе, чтобы определенные значки отображались именно тогда, когда они фактически отображаются.

SVG SpriteТехнические передовые практики:

  • использоватьsymbolЗначки интеграции элементов
  • использоватьuseэлементы для использования значков

Пример использования:

<svg>
	<!-- symbol definition  NEVER draw -->
	<symbol id="sym01" viewBox="0 0 150 110">
	  <circle cx="50" cy="50" r="40" stroke-width="8" stroke="red" fill="red"/>
	  <circle cx="90" cy="60" r="40" stroke-width="8" stroke="green" fill="white"/>
	</symbol>
	
	<!-- actual drawing by "use" element -->
	<use xlink:href="#sym01"
	     x="0" y="0" width="100" height="50"/>
	<use xlink:href="#sym01"
	     x="0" y="50" width="75" height="38"/>
	<use xlink:href="#sym01"
	     x="0" y="100" width="50" height="25"/>
</svg>

Компонентный SvgIcon

на основеVueИнкапсулированные компоненты SVG ICON

// @/components/SvgIcon.vue
<template>
  <svg :class="svgClass" aria-hidden="true" v-on="$listeners">
    <use :xlink:href="iconName" />
  </svg>
</template>
    
<script>
export default {
  name: 'SvgIcon',
  props: {
    iconClass: {
      type: String,
      required: true
    },
    className: {
      type: String,
      default: ''
    }
  },
  computed: {
    iconName() {
      return `#icon-${this.iconClass}`
    },
    svgClass() {
      return 'svg-icon ' + this.className
    }
  }
}
</script>
    
<style scoped>
.svg-icon {
  width: 1em;
  height: 1em;
  vertical-align: -0.15em;
  fill: currentColor;
  overflow: hidden;
}
</style>

Автоматическое введение SVG

Динамически импортировать все значки в src/assets/icons

// @/plugins/svgicon.js
import Vue from 'vue'
import SvgIcon from '@/components/SvgIcon'
    
Vue.component('svg-icon', SvgIcon)
    
const requireAll = requireContext => requireContext.keys().map(requireContext)
    
const svgIcons = require.context('./components', false, /\.svg$/)
requireAll(svgIcons)

Упаковка спрайтов SVG

мы можем использоватьsvg-sprite-loaderэтот плагин для созданияSVG Sprite, введите значок svg с помощью компонентов.

на основеWebpack 3.xМетод настройки следующий:

// 通过 exclude/include 来区分哪些属于svg icon,哪些属于image
{
  test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
  loader: 'url-loader',
  exclude: [resolve('src/assets/icons')],
  options: {
    limit: 10000,
    name: utils.assetsPath('img/[name].[hash:7].[ext]')
  }
},
{
  test: /\.svg$/,
  loader: 'svg-sprite-loader',
  include: [resolve('src/assets/icons')],
  options: {
    symbolId: 'icon-[name]'
  }
}

Суммировать

Ключевые моменты этой оптимизации производительности:

Сторона веб-пакета:

  • Включите Gzip, прямая выгода относительно велика
  • Используйте плагин предварительной загрузки, чтобы предварительно объявить ресурсы, которые будут использоваться.
  • Максимально оптимизируйте пакет, загружайте его по требованию и уменьшайте размер пакета.

Сеть:

  • Лучше всего обновить сервер до HTTP2 в сочетании с HTTPS.
  • При использовании стратегии кэширования HTTP наилучшая производительностьне спрашивай

Vue практические аспекты:

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

С точки зрения ресурсов:

  • Когда в проекте используется больше SVG, вы можете использовать технологию «SVG Sprite» для управления

Наконец

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

Я хотел бы позаимствовать из The Definitive Guide to Web Performance,Ilya GrigorikУпоминается: «💡Мы заботимся не только о предоставлении полезных приложений, наша цель — обеспечить наилучшую производительность!», чтобы обобщить практику оптимизации производительности и напомнить себе, что при работе над точка проекта.

Ссылаться на

Полное руководство по веб-производительности

оригинальный🚀 Помните об оптимизации производительности интерфейса