Для интерфейсных страниц загрузка статических ресурсов играет решающую роль в производительности страницы. В этой статье будут представлены две инструкции ресурсов, предоставляемые браузером — предварительная загрузка/предварительная выборка, которые могут помочь браузеру оптимизировать порядок и время загрузки ресурсов и повысить производительность страницы.
1. Начните с примера
Как показано на рисунке выше, мы разработали простую кассу.В процессе оплаты вы можете расширить список купонов, чтобы выбрать соответствующий купон. Как видно из анимации, когда список расширяется в первый раз, постепенно отображается фон купона, что не очень хорошо.
Причина проблемы также очевидна.Поскольку в качестве фона используется специально разработанное изображение, изображение необходимо загрузить при расширении списка купонов.Процесс выцветания фона на самом деле является процессом загрузки изображения, когда скорость сети низкая. , эта проблема возникнет более очевидно. Итак, как решить эту проблему?
После тщательного анализа мы обнаружим, что причина проблемы в том, что фоновое изображение загружается слишком поздно.
Если фоновое изображение может быть загружено до отображения списка купонов, этой проблемы не возникнет. Исходя из этой идеи, мы можем думать о следующих двух решениях:
- Используйте встроенные изображения, то есть преобразуйте изображение в URL-адрес данных в кодировке base64. Таким образом, информация об изображении фактически интегрируется в файл css, что позволяет избежать отдельной загрузки ресурсов изображения. Однако встраивание изображения увеличит размер файла CSS и увеличит время рендеринга первого экрана.
- Используйте код js для предварительной загрузки изображений
preloadImage() {
const imgList = [
require('@/assets/imgs/error.png'),
require('@/assets/imgs/ticket_bg.png')
];
for (let i = 0; i < imgList.length; i++) {
const newIMG = new Image();
newIMG.src = imgList[i];
}
}
Это решение в основном использует механизм кеша браузера, а код js загружает соответствующее изображение заранее в определенное время, а список купонов можно напрямую получить из кеша при его рендеринге. Однако это решение добавляет дополнительный код, вам нужно самостоятельно контролировать время загрузки и жестко закодировать URL-адрес изображения в логике.
Видно, что два приведенных выше решения могут решить нашу проблему, но есть некоторые недостатки.
Итак, есть ли лучшее решение? Ответ: предварительная выборка — схема предварительной загрузки, изначально предоставляемая браузером.
2. Что такое предварительная выборка?
prefetch (предварительная выборка ссылок) — это механизм браузера, который использует время простоя браузера для загрузки или предварительной выборки документов, к которым пользователь может получить доступ в ближайшем будущем. Веб-страница предоставляет браузеру набор подсказок предварительной выборки и начинает молча извлекать указанный документ и сохранять его в кэше после того, как браузер завершит загрузку текущей страницы. Когда пользователь получает доступ к одному из предварительно загруженных документов, его можно быстро извлечь из кеша браузера. --MDN
В частности, браузеры реализуют предварительную загрузку через теги.
Среди них rel="prefetch" называется Resource-Hints (подсказки ресурсов), которые представляют собой инструкции, помогающие браузеру в оптимизации ресурсов.
Аналогичные директивы — это rel="preload", о которых мы упомянем позже.
<head>
...
<link rel="prefetch" href="static/img/ticket_bg.a5bb7c33.png">
...
</head>
Посмотрите, как загружается текущий список купонов.
Конечно же, мы успешно добились желаемого эффекта. Так как же это делает браузер? Давайте откроем панель сети Chrome, чтобы узнать:
Видно, что запрос на загрузку фонового изображения купона ticket_bg.png уже появился в списке запросов на первом экране, а сам запрос ничем не отличается от обычного запроса, после расширения списка купонов появляется новый ticket_bg Добавив в сеть png запрос на доступ, мы быстро обнаружили, что хотя статус этого запроса тоже 200, но есть специальная пометка — prefetch cache, указывающая на то, что запрошенный на этот раз ресурс исходит из prefetch cache. Эта производительность подтверждает приведенное выше определение предварительной выборки, то есть браузер предварительно загружает ресурсы во время простоя и быстро извлекает их непосредственно из кеша браузера, когда они фактически используются.
3. Предварительная загрузка
Из приведенного выше случая мы поняли мощную способность браузера предварительно загружать ресурсы. На самом деле предварительная загрузка — это широкое понятие, а предварительная выборка — это лишь один из конкретных методов реализации.В этом разделе мы представим еще один метод предварительной загрузки — предварительную загрузку. Как упоминалось выше, предварительная загрузка и предварительная выборка относятся к Resource-Hints браузера, которые используются для помощи браузеру в оптимизации ресурсов. Чтобы различать их, предварительная выборка обычно переводится как предварительная выборка, а предварительная загрузка — как предварительная загрузка.
Предварительная загрузка значения атрибута атрибута rel элемента позволяет вам писать некоторые декларативные запросы на выборку ресурсов внутри элемента на вашей HTML-странице, которые могут указать, какие ресурсы необходимы сразу после загрузки страницы. Для такого немедленно необходимого ресурса вы можете начать извлекать его в начале жизненного цикла загрузки страницы, предварительно загружая его до того, как будет задействован основной механизм рендеринга браузера. Этот механизм позволяет загружать ресурсы и делать их доступными раньше и с меньшей вероятностью блокирует первоначальный рендеринг страницы, тем самым повышая производительность.
Проще говоря, это явное объявление высокоприоритетного ресурса через тег, заставляющий браузер запрашивать ресурс заранее, не блокируя нормальную загрузку документа. Мы также используем практический случай для подробного ознакомления.
На картинке выше еще одна касса, которую мы разработали, для локализации в дизайне использован нестандартный шрифт. После завершения разработки мы обнаружили, что при первой загрузке страницы текст будет мигать в течение короткого периода времени (FOUT, Flash of Unstyled Text), что более очевидно при плохих условиях сети (как показано на анимации). Причина в том, что файл шрифта импортируется с помощью CSS и будет загружен после анализа CSS.До завершения загрузки браузер может использовать только шрифт с пониженной версией. Другими словами, время загрузки файла шрифта слишком позднее, и браузеру нужно указать, чтобы он загружался заранее, и именно здесь вступает в действие предварительная загрузка.
Добавляем тег preload в заголовок html-файла записи:
<head>
...
<link rel="preload" as="font" href="<%= require('/assets/fonts/AvenirNextLTPro-Demi.otf') %>" crossorigin>
<link rel="preload" as="font" href="<%= require('/assets/fonts/AvenirNextLTPro-Regular.otf') %>" crossorigin>
...
</head>
Посмотрите еще раз на эффект от первой загрузки страницы:
Феномен мигания стиля шрифта исчез! Давайте сравним сетевую панель до и после использования предварительной загрузки.
перед использованием:
После использования:
Можно обнаружить, что время загрузки файла шрифта значительно раньше, и он загружается вскоре после того, как браузер получает html.
Примечание. В ссылке предварительной загрузки должен быть установлен атрибут as для объявления типа ресурса (шрифт/изображение/стиль/скрипт и т. д.), иначе браузер может неправильно загрузить ресурс.
В-четвертых, конкретная практика Preload и Prefetch.
1. предварительная загрузка-веб-пакет-плагин
Два примера, которые мы привели в предыдущей статье, заключаются в том, чтобы вручную добавить соответствующий код в html записи:
<head>
...
<link rel="prefetch" href="static/img/ticket_bg.a5bb7c33.png">
...
</head>
<head>
...
<link rel="preload" as="font" href="<%= require('/assets/fonts/AvenirNextLTPro-Demi.otf') %>" crossorigin>
<link rel="preload" as="font" href="<%= require('/assets/fonts/AvenirNextLTPro-Regular.otf') %>" crossorigin>
...
</head>
Это явно не удобно, а путь к ресурсу жестко прошит в странице (на самом деле хеш в суффиксе ticket_bg.a5bb7c33.png генерируется автоматически в процессе построения, так что сам метод хардкодинга не сработает во многих сценариях). Плагин webpack preload-webpack-plugin может помочь нам автоматизировать этот процесс и вставлять теги ссылок в процесс сборки в сочетании с htmlWebpackPlugin.
const PreloadWebpackPlugin = require('preload-webpack-plugin');
...
plugins: [
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: 'asyncChunks', // preload模块范围,还可取值'initial'|'allChunks'|'allAssets',
fileBlacklist: [/\.svg/] // 资源黑名单
fileWhitelist: [/\.script/] // 资源白名单
})
]
Настройка PreloadWebpackPlugin в целом относительно проста, и необходимо обратить внимание на атрибут include. Значение по умолчанию для этого свойства — «asyncChunks», что означает, что предварительно загружаются только асинхронные js-модули; если вам нужно предварительно загрузить такие ресурсы, как изображения и шрифты, вам нужно установить для него значение «allAssets», что означает, что все типы ресурсов обрабатываются.
Но в целом мы не хотим слишком сильно расширять диапазон предзагрузки, поэтому нам нужно управлять им через fileBlacklist или fileWhitelist.
Для асинхронно загружаемых модулей более детальное управление также доступно с помощью встроенного в webpack флага /_ webpackPreload: true _/.
В качестве примера возьмем следующий код: webpack сгенерирует теги для добавления в заголовок html-страницы.
import(/* webpackPreload: true */ 'AsyncModule');
Примечание. Настройка предварительной выборки аналогична настройке предварительной загрузки, но нет необходимости устанавливать атрибут as.
2. Сценарии использования
Как видно из предыдущего введения, изначальной целью предварительной загрузки является загрузка ключевых ресурсов, необходимых для первого экрана, как можно быстрее, тем самым повышая производительность рендеринга страницы.
В настоящее время браузеры в основном имеют возможности предиктивного синтаксического анализа, которые могут заранее анализировать ресурсы внутри и вне входного html, поэтому файлы сценариев входа, файлы стилей и т. д. не нужно предварительно загружать.
Однако некоторые ресурсы, скрытые в CSS и JavaScript, такие как файлы шрифтов, сами по себе являются ключевыми ресурсами в верхней части страницы, но загружаются браузером только после анализа файла CSS. Этот сценарий подходит для объявления предварительной загрузки для загрузки ресурсов как можно раньше, чтобы избежать задержки рендеринга страницы.
В отличие от предварительной загрузки, предварительная выборка объявляет ресурсы, к которым можно получить доступ в будущем, поэтому она подходит для кэширования ресурсов асинхронно загружаемых модулей и других страниц маршрутизации, на которые можно перейти; для некоторых ресурсов, к которым, вероятно, будет доступ в будущем, таких как купоны в приведенном выше случае Фоновое изображение списка, общий значок сбоя загрузки и т. д. также более подходят.
3. Лучшие практики
Основываясь на описанных выше сценариях использования, мы можем резюмировать более общий передовой опыт:
- В большинстве сценариев нет необходимости использовать предварительную загрузку.
- Рекомендуется использовать предварительную загрузку для ключевых ресурсов в верхней части страницы, таких как файлы шрифтов, скрытые в сценариях и стилях.
- Модули, которые загружаются асинхронно (обычно это не первые страницы в одностраничной системе), рекомендуется использовать предварительную выборку.
- Ресурсы, к которым скоро будет доступ с высокой вероятностью, могут использовать предварительную выборку для повышения производительности и удобства.
4. Конфигурация vue-cli3 по умолчанию
- preload
По умолчанию приложение Vue CLI автоматически генерирует запросы предварительной загрузки для всех файлов, необходимых для первоначального рендеринга. Эти подсказки вводятся @vue/preload-webpack-plugin и могут быть изменены и удалены с помощью config.plugin('preload') chainWebpack.
- prefetch
По умолчанию приложение Vue CLI автоматически генерирует подсказки предварительной выборки для всех файлов JavaScript, сгенерированных как асинхронные фрагменты (продукт разделения кода по требованию с помощью динамического импорта()). Эти подсказки вводятся @vue/preload-webpack-plugin и могут быть изменены и удалены с помощью config.plugin('prefetch') chainWebpack.
Пять, резюме и наступление на яму
1. Суть preload и prefetch заключается в предварительной загрузке, то есть сначала в загрузке, затем в выполнении и развязывании загрузки и выполнения.
2. Предварительная загрузка и предварительная выборка не блокируют загрузку страницы.
3. Предварительная загрузка используется для объявления ключевых ресурсов текущей страницы, заставляя браузер загружаться как можно быстрее, в то время как предварительная выборка используется для объявления ресурсов, которые могут быть использованы в будущем, и загрузки их, когда браузер бездействует.
4. Не злоупотребляйте preload и prefetch, их нужно использовать в соответствующих сценариях.
5. Атрибут crossorigin должен быть установлен для ресурса шрифта предварительной загрузки, иначе это вызовет повторную загрузку.
Причина в том, что если атрибут crossorigin не указан (даже если это одно и то же происхождение), браузер будет использовать CORS в анонимном режиме для предварительной загрузки, так что два запроса не могут совместно использовать кеш.
6. Что касается кэширования ресурсов предварительной загрузки и предварительной выборки, это объясняется в статье разработчиков Google: Если ресурс можно кэшировать (например, есть допустимый cache-control и max-age), он сохраняется в HTTP кеш (он же дисковый кеш), который может использоваться текущими или будущими задачами; если ресурс не может быть закэширован в кеше HTTP, вместо этого он помещается в кеш памяти до использования.
Однако, когда мы тестировали его в Chrome (версия 80), это было не так. Установите политику кэширования сервера на отсутствие сохранения и наблюдайте за загрузкой ресурсов.
Можно обнаружить, что вторая загрузка ticket_bg.png получается не из локального кеша, а все равно загружается с сервера. Поэтому, если вы хотите использовать предварительную выборку, соответствующие ресурсы должны быть правильно кэшированы.
7. Сайты без действующего https-сертификата не могут использовать предварительную выборку, а предварительно выбранные ресурсы не будут кэшироваться (при фактическом использовании причина неизвестна).
8. Наконец, давайте взглянем на совместимость браузеров с предварительной загрузкой и предварительной выборкой.
Видно, что совместимость между ними в настоящее время не очень хорошая. К счастью, браузеры, которые не поддерживают предварительную загрузку и предварительную выборку, будут автоматически игнорировать их, поэтому их можно использовать в качестве функции прогрессивного улучшения для оптимизации загрузки ресурсов наших страниц, повышения производительности и удобства пользователей.
Автор: Ша Чаохэн