Оптимизация производительности внешнего интерфейса - с более чем 10 секунд до 1,05 секунды

внешний интерфейс сервер JavaScript браузер
Оптимизация производительности внешнего интерфейса - с более чем 10 секунд до 1,05 секунды

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

упомянутьОптимизация производительности интерфейса, каждый должен думатьYahoo военный, эта статья будет сочетатьYahoo военныйВключайте собственные знания, обобщайте и разбирайтесь 😜

За подробностями обращайтесь к моемублог lishaoy.net

Во-первых, давайте посмотрим 👀Yahoo военныйиз35полоска.

  1. Минимизируйте количество HTTP-запросов — компромисс
  2. использоватьCDN(Сеть доставки контента)
  3. Обозначенный как заголовок Expires или Cache-Control, содержимое имеет кеш.
  4. Избегайте пустых src и href
  5. Сжать содержимое с помощью gzip
  6. Поместите CSS сверху
  7. Поместите JS в самый низ
  8. Избегайте использования выражений CSS
  9. Поместите CSS и JS во внешние файлы
  10. Сокращение запросов DNS
  11. Минифицировать CSS и JS
  12. избегать прыжков
  13. Удалите дубликаты JS и CSS
  14. Настройка ETag
  15. Сделать AJAX кэшируемым
  16. Очистить выходной буфер как можно раньше
  17. Используйте GET для выполнения запросов AJAX.
  18. ленивая загрузка
  19. Предварительная загрузка
  20. Уменьшите количество элементов DOM
  21. Разделите содержимое страницы по доменному имени
  22. Минимизируйте количество iframe
  23. Избегайте 404
  24. Уменьшить размер файла cookie
  25. Использовать домен без файлов cookie
  26. Уменьшить доступ к DOM
  27. Разработка интеллектуальных обработчиков событий
  28. Замените @import на
  29. Избегайте использования фильтров
  30. Оптимизация изображений
  31. Оптимизация CSS Spirite
  32. Не масштабируйте изображения в HTML — компромиссы
  33. favicon.ico маленький и кешируемый
  34. Размер одного контента не должен превышать 25 КБ.
  35. Упаковать компоненты в составной текст

Если даYahoo военныйКонкретные детали контента не очень знакомы, вы можете пойти в каждый поиск 🔍 двигатель самостоятельно, поискYahoo военныйУзнать больше.

сжать слияние

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

  • Уменьшить количество сетевых запросов
  • Уменьшить размер файла
  • использоватьCDNускорить

таксжимать, сливатьсяэто решение, конечно, вы можете использоватьgulp,webpack,gruntи т. д. инструменты для сборкисжимать, сливаться

JS、CSSсжать слияние

Например:gulp js、cssСожмите и объедините код следующим образом 👇

//压缩、合并js
gulp.task('scripts', function () {
    return gulp.src([
        './public/lib/fastclick/lib/fastclick.min.js',
        './public/lib/jquery_lazyload/jquery.lazyload.js',
        './public/lib/velocity/velocity.min.js',
        './public/lib/velocity/velocity.ui.min.js',
        './public/lib/fancybox/source/jquery.fancybox.pack.js',
        './public/js/src/utils.js',
        './public/js/src/motion.js',
        './public/js/src/scrollspy.js',
        './public/js/src/post-details.js',
        './public/js/src/bootstrap.js',
        './public/js/src/push.js',
        './public/live2dw/js/perTips.js',
        './public/live2dw/lib/L2Dwidget.min.js',
        './public/js/src/love.js',
        './public/js/src/busuanzi.pure.mini.js',
        './public/js/src/activate-power-mode.js'
    ]).pipe(concat('all.js')).pipe(minify()).pipe(gulp.dest('./public/dist/'));
});

// 压缩、合并 CSS 
gulp.task('css', function () {
    return gulp.src([
        './public/lib/font-awesome/css/font-awesome.min.css',
        './public/lib/fancybox/source/jquery.fancybox.css',
        './public/css/main.css',
        './public/css/lib.css',
        './public/live2dw/css/perTips.css'
    ]).pipe(concat('all.css')).pipe(minify()).pipe(gulp.dest('./public/dist/'));
});

Затем положитесжимать, сливатьсяизJS、CSSположить вCDN, 👀 чтобы увидеть, как это работает

Как показано: *сжимать, сливатьсяи положить вCNDПостэффекты *

首页请求速度(js) 首页请求速度(css)

Вышеlishaoy.netпосле очистки кешатитульная страницаскорость запроса.

Видно, что время запроса равно4.59 s, общее количество запросов51, а такжеjsКоличество запросов8,cssКоличество запросов3 (На самом деле там только один all.css, а два других подгружает гугл браузер), Вместо того, чтобы использоватьсжимать, сливатьсякогда время запроса10Более секунды, общее количество запросов70несколько,jsКоличество запросов20Несколько , сравните время запросапредставлениепродвигать1 размного

Как показано на рисунке:Эффект домашней страницы с кешем

首页请求速度(缓存)

В основном открывается за секунды 😝

Советы: всжимать, сливатьсяПосле этого один файл управляется примерно на 25~30 Кб, и под одним доменом лучше не иметь более 5 ресурсов

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

Например:gulpКод сжатия изображения выглядит следующим образом 👇

//压缩image
gulp.task('imagemin', function () {
    gulp.src('./public/**/*.{png,jpg,gif,ico,jpeg}')
        .pipe(imagemin())
        .pipe(gulp.dest('./public'));
});

Объединить изображения можно с помощьюCSS Spirite, метод заключается в использовании небольших изображений сPSДля синтеза изображения используйтеcssопределить, где отображается каждое изображение

.top_right .phone {
	background: url(../images/top_right.png) no-repeat 7px -17px;
	padding: 0 38px;
}

.top_right .help {
	background: url(../images/top_right.png) no-repeat 0 -47px;
	padding: 0 38px;
}

Затем положитекомпрессиякартинки вCDN, 👀 посмотрите, как это работает

首页请求速度(images)

Видно, что время запроса равно1.70 s, общее количество запросов50, а такжеimgКоличество запросов15 (Поскольку главная страница заполнена большими картинками, они не объединены, а сжаты)Однако эффект очень хороший 😀, от4.59 sсократить до1.70 s, производительность удваивается.

Посмотрим как там кеш 😏

首页请求速度(images 缓存)

время запроса1.05 s, с кешем и без него в принципе одно и то же

Советы: Для больших изображений в разных терминалах следует использовать разные разрешения вместо масштабирования (в процентах).

весьсжимать, сливаться (js, css, изображение)вставить сноваCDN, время запроса начинается с10много секунд, до конца1.70 s, улучшение производительности5Еще раз видно, что эта операция необходима.

тайник

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

  • Уменьшите соответствующую задержку и улучшите время отклика
  • Уменьшите потребление пропускной способности сети и сэкономьте трафик

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

первый запрос браузера

no-shadow
первый запрос

Браузер снова запрашивает

no-shadow
запросить снова

Из приведенных выше двух картинок вы можете четко понять, что такое браузер.тайникпроцесс. Посетите один в первый разURL,неттайник, однако сервер отвечает некоторымиheaderтакая информация, как:expires、cache-control、last-modified、etagПодождите, чтобы записать, кэшируется ли следующий запрос и как его кэшировать. посетите это сноваURLвремя, браузер вернется на основе первого посещенияheaderинформацию, чтобы решить, нужно ли и как кэшировать. Давайте сосредоточимся на анализе второй картинки, которая на самом деле разделена на две строки следующим образом 👇

  • Первая строка:Когда браузер посещаетURL, ресурс будет получен первымheaderинформация, чтобы определить, следует ли попадать в надежный кэш(кэш-контроль и срок действия), такие как попадание, получить ресурс непосредственно из кеша, включая ответheaderИнформация(Запрос не будет связываться с сервером), то есть,Сильный кеш, как показано на рисунке
强缓存
  • Вторая линия:Если у вас нет удараСильный кеш, браузер отправит запрос на сервер, и запрос будет содержать информацию, связанную с кешем, возвращенную первым запросом.headerИнформация(Последнее изменение/Если-изменено-с момента и Etag/Если-нет-совпадения), сервером согласно корреляции в запросеheaderИнформация для сравнения результатов для согласования попадания в кеш; при попадании сервер возвращает новый ответheaderВ соответствии с обновлением информации о кешеheaderинформацию, но не возвращает содержимое ресурса, он сообщит браузеру, что его можно получить непосредственно из кеша; в противном случае он вернет самое последнее содержимое ресурса, т.е.Согласовать кеш.

Теперь мы узнали, что механизм кэширования браузера делится наСильный кеш, кеш согласования, и посмотрите на их отличия 👇

стратегия кэширования Получить форму ресурса код состояния отправить запрос на сервер
Сильный кеш получить из кеша 200 (из кеша памяти) Нет, возьмите прямо из кэша
Согласовать кеш получить из кеша 304 (без изменений) Да, сообщить серверу, доступен ли кеш

Сильный кеш

связанные с сильным кэшированиемheaderЕсть два поля:

expires

истекает:Этоhttp1.0спецификация времени, его значение - абсолютное времяGMTСтрока времени в формате, напримерMon, 10 Jun 2015 21:31:12 GMT, если время отправки запросаexpiresраньше локальный кеш всегда действителен, иначе на сервер отправляется запрос на получение ресурса

cache-control

cache-control: max-age=number,Этоhttp1.1появился, когдаheaderинформация, в основном с использованием этого поляmax-ageЭто относительное значение; время первого запроса ресурса иCache-ControlУстановите срок действия, рассчитайте время истечения ресурса, а затем сравните это время истечения с текущим временем запроса.Если время запроса предшествует времени истечения срока действия, кеш может попасть, в противном случае он будет пропущен.cache-controlВ дополнение к этому полю существуют следующие наиболее часто используемые значения параметров:

  • без кеша:Не используйте локальный кеш. Необходимо использовать согласование кеша, сначала подтвердите с сервером, был ли изменен возвращаемый ответ, если есть предыдущий ответETag, то запрос будет сверяться с сервером, и если ресурс не был изменен, повторной загрузки можно избежать.
  • No-Store:Напрямую запретить браузеру кешировать данные, каждый раз, когда пользователь запрашивает ресурс, на сервер будет отправляться запрос, и каждый раз будет загружаться весь ресурс.
  • публичный:Может кэшироваться всеми пользователями, включая конечных пользователей иCDNДождитесь промежуточного прокси-сервера.
  • частный:Может кэшироваться только браузером конечного пользователя, не разрешеноCDNПодождите, пока сервер кэширования ретрансляции закэширует его.

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

Согласовать кеш

Кэш согласования согласовывается браузером и сервером, чтобы определить, следует ли кэшировать или нет. Согласование в основном проходит через следующие две группы.headerПоля, эти два набора полей появляются парами, то есть поле включается в заголовок ответа первого запроса.(Last-ModifiedилиEtag), последующий запрос принесет соответствующее поле запроса(If-Modified-SinceилиIf-None-Match), если заголовок ответа неLast-ModifiedилиEtagполе, в заголовке запроса не будет соответствующего поля.

Last-Modified/If-Modified-Since

Ценность обоихGMTСтрока времени в формате конкретного процесса:

  • Браузер запрашивает ресурс у сервера в первый раз, и сервер одновременно возвращает ресурс.responeизheaderплюсLast-Modifiedполе, этоheaderПоле указывает время последней модификации данного ресурса на сервере

  • Когда браузер снова запросит ресурс с сервера,requestизheaderдобавитьIf-Modified-Sinceполе, этоheaderЗначение поля — это то, что было возвращено в последнем запросе.Last-Modifiedзначение

  • Когда сервер снова получает запрос ресурса, согласно браузеруIf-Modified-Sinceи время последней модификации ресурса на сервере, чтобы определить, изменился ли ресурс, и вернуться, если изменений нет304 Not Modified, но содержимое ресурса не будет возвращено; если есть изменение, содержимое ресурса будет возвращено в обычном режиме. когда сервер вернется304 Not Modifiedотклик,response headerне будет добавлено вЗаголовок Last-Modified, так как ресурс не меняется, тоLast-ModifiedЭто не изменится, это то, что возвращает сервер304времяresponse header

  • браузер получает304ответ, ресурс загружается из кеша

  • Если согласованный кеш отсутствует, и браузер загружает ресурс напрямую с сервера,Last-ModifiedизHeaderОн будет обновлен при перезагрузке и при следующем запросе.If-Modified-Sinceвключит последний возвращенныйLast-Modifiedстоимость

Etag/If-None-Match

Эти два значения являются уникальной строкой идентификации каждого ресурса, сгенерированного сервером, и это значение будет меняться до тех пор, пока изменяется ресурс; процесс оценки такой же, как иLast-Modified, If-Modified-Sinceпохожий наLast-ModifiedРазница в том, что когда сервер возвращается304 Not Modifiedответ, из-заETagрегенерированный,response headerтоже поставлю этоETagвернуться, даже если этоETagНикаких изменений по сравнению с предыдущим.

Советы: Last-Modified и ETag можно использовать вместе. Сервер сначала проверит ETag. Если он непротиворечив, он продолжит сравнение Last-Modified и, наконец, решит, возвращать ли 304.

Service Worker

Что такое сервисный работник

Service Worker本质上充当Web应用程序与浏览器之间的代理服务器,也可以在网络可用时作为浏览器和网络间的代理。 Они предназначены (среди прочего) для обеспечения эффективного автономного взаимодействия, перехвата сетевых запросов и выполнения соответствующих действий в зависимости от того, доступна ли сеть и находится ли обновленный ресурс на сервере. Они также предоставляют доступ к push-уведомлениям и API фоновой синхронизации.

Service workerОн может решить проблемы текущих автономных приложений и в то же время может сделать больше.Service Workerweb app,РоднойappОсновная причина популярности.

Посмотрим еще раз 👀service workerЧто может быть сделано:

  • фоновый обмен сообщениями
  • Веб-прокси, переадресация запросов, подделка ответов
  • Автономный кеш
  • сообщение
  •  …

Эта статья в основном посвящена (lishaoy.net) кеш ресурсов в качестве примера для иллюстрации того, как работают сервис-воркеры

Жизненный цикл

service workerЖизненный цикл начальной установки, как показано на рисунке 🌠

no-shadow
ПО жизненный цикл

Как видно из рисунка выше 👆,service workerРабочий процесс:

  1. Установить: service worker URLпройти черезserviceWorkerContainer.register()приобрести и зарегистрировать.
  2. активация:когдаservice workerПосле завершения установки приходит событие активации.onactivateОсновное использование — очистка предыдущих версийservice workerРесурсы, используемые в сценариях.
  3. монитор:два состояния
    • Прекращено, чтобы сохранить память;
    • приобретение монитораfetchи сообщениеmessageмероприятие.
  4. разрушать:Нужно ли уничтожать, определяется браузером, еслиservice workerЕсли он не используется в течение длительного времени или память машины ограничена, он может быть уничтожен.worker.

Советы. После успешного выполнения в браузере Chrome вы можете получить доступ к chrome://inspect/# service-workers и chrome://serviceWorker-INTERNALS/ к текущему запущенному Service Worker, как показано на рисунке 👇.

service worker

Теперь давайте напишем простой пример🌰

Зарегистрировать сервисного работника

установитьservice worker, вам необходимо зарегистрировать его на своей странице. Этот шаг сообщает браузеру, что вашservice workerгде скрипт.

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js').then(function(registration) {
    // Registration was successful
    console.log('ServiceWorker registration successful with scope: ',    registration.scope);
  }).catch(function(err) {
    // registration failed :(
    console.log('ServiceWorker registration failed: ', err);
  });
}

Приведенный выше код проверяетservice worker APIДоступен ли он, если он доступен,service worker /sw.jsзарегистрирован. если этоservice workerУже зарегистрированный браузер автоматически проигнорирует приведенный выше код.

Активировать сервис-воркер

В твоемservice workerПосле регистрации браузер попытается установить и активировать его для вашей страницы или сайта.installСобытие срабатывает после завершения установки.installСобытия обычно используются для заполнения возможностей автономного кэша вашего браузера. тебе следуетinstallсобытие определяетcallbackи решите, какие файлы вы хотите кэшировать.

// The files we want to cache
var CACHE_NAME = 'my-site-cache-v1';
var urlsToCache = [
  '/',
  '/css/main.css',
  '/js/main.js'
];

self.addEventListener('install', function(event) {
  // Perform install steps
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(function(cache) {
        console.log('Opened cache');
        return cache.addAll(urlsToCache);
      })
  );
});

в нашемinstall callback, нам необходимо выполнить следующие шаги:

  • включить кеш
  • Кэшировать наш файл
  • Определяет, должны ли все ресурсы кэшироваться

В приведенном выше коде мы передаемcaches.openОткройте наш назначенныйcacheимя файла, затем мы вызываемcache.addAllи передать наш массив файлов. Это через сериюpromise (кеши.open и cache.addAll)Завершенный.event.waitUntilполучить одинpromiseИ используйте его, чтобы узнать, сколько времени заняла установка и была ли установка успешной.

работник службы прослушивания

Теперь, когда мы кэшировали ресурсы вашего сайта, вам нужно сообщитьservice workerПусть он что-то делает с кэшированным содержимым. имеютfetchсобытия, это легко сделать.

каждый раз, когдаservice workerКогда ресурс требуется контролировать, будет вызватьfetchсобытия, мы можем датьservice workerдобавить одинfetchпрослушиватель событий, затем вызовитеeventВверхrespondWith()способы захвата нашегоHTTPОтветы, а затем вы можете обновить их своими методами.

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request);
  );
});

caches.match(event.request)позволяют нам запрашивать ресурсы из сети иcacheСопоставьте ресурсы, доступные в кеше, чтобы увидеть, есть ли в кеше соответствующие ресурсы. Этот матч проходитurlа такжеvary headerпродолжайте как обычноHTTPПросьба так же.

Итак, как мы вернемсяrequestНу а следующий 👇 пример 🌰

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request)
      .then(function(response) {
        // Cache hit - return response
        if (response) {
          return response;
        }

        return fetch(event.request);
      }
    )
  );
});

В приведенном выше коде мы определяемfetchсобытие, вevent.respondWith, мы проходим черезcaches.matchпроизведеноpromise.caches.matchнайтиrequestв одеялеservice workerпопадание в кешresponse. 如果我们有一个命中的responseМы возвращаем кэшированную ценность, в противном случае мы возвращаем запрос из сети в режиме реального времениfetchрезультат.

sw-toolbox

Конечно, я также могу использовать сторонние библиотеки, такие как:lishaoy.netиспользовалsw-toolbox.

sw-toolboxОн очень прост в использовании, следующий 👇lishaoy.netПример 🌰

  "serviceWorker" in navigator ? navigator.serviceWorker.register('/sw.js').then(function () {
    navigator.serviceWorker.controller ? console.log("Assets cached by the controlling service worker.") : console.log("Please reload this page to allow the service worker to handle network operations.")
  }).catch(function (e) {
    console.log("ERROR: " + e)
  }) : console.log("Service workers are not supported in the current browser.")

ВышерегистрОдинservice woker

"use strict";
(function () {
    var cacheVersion = "20180527";
    var staticImageCacheName = "image" + cacheVersion;
    var staticAssetsCacheName = "assets" + cacheVersion;
    var contentCacheName = "content" + cacheVersion;
    var vendorCacheName = "vendor" + cacheVersion;
    var maxEntries = 100;
    self.importScripts("/lib/sw-toolbox/sw-toolbox.js");
    self.toolbox.options.debug = false;
    self.toolbox.options.networkTimeoutSeconds = 3;

    self.toolbox.router.get("/images/(.*)", self.toolbox.cacheFirst, {
        cache: {
            name: staticImageCacheName,
            maxEntries: maxEntries
        }
    });

    self.toolbox.router.get('/js/(.*)', self.toolbox.cacheFirst, {
        cache: {
            name: staticAssetsCacheName,
            maxEntries: maxEntries
        }
    });
    self.toolbox.router.get('/css/(.*)', self.toolbox.cacheFirst, {
        cache: {
            name: staticAssetsCacheName,
            maxEntries: maxEntries
        }
    
    ......

    self.addEventListener("install", function (event) {
        return event.waitUntil(self.skipWaiting())
    });
    self.addEventListener("activate", function (event) {
        return event.waitUntil(self.clients.claim())
    })
})();

Вот и все 🍉(Конкретное использование может перейти кsw-toolboxПроверить)

Некоторые студенты спросили,service workerТак просто в использовании, насколько велик этот кеш-память? Фактически, вChromeможно увидеть, как показано на рис.

fstorage quota

Видно, что, вероятно,30G, мой сайт использует только183MB, вполне достаточно 🍓

Напоследок две картинки

from ServiceWorker Cache Storage

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

  • блокированный вывод bigpipe
  • рендеринг блока bigrender
  • ...

так же как,оказыватьоптимизации, такие как

  • requestAnimationFrame
  • well-change
  • Аппаратное ускорение графического процессора
  • ...

и инструменты тестирования производительности, такие как

  • PageSpeed
  • audits
  • ...