Новые розничные товары в приложении Ele.me в основном основаны на изображениях, которые подсказывают пользователям щелкнуть рекламный столбец карусели или список магазинов, чтобы перейти на страницу назначенного продукта.Поэтому страница содержит большое количество изображений, таких как столбец рекламы карусели под окном поиска, полоса продвижения посередине и список магазинов внизу имеют много отображаемых изображений в этих областях. Поэтому скорость загрузки изображения напрямую влияет на скорость загрузки страницы. Далее будет объяснено, как оптимизировать загрузку новых розничных изображений с двух точек зрения: проблемы, причины и решения при загрузке изображений.
Все данные и изображения в этой статье получены черезCharlesПолучено путем моделирования сетевой среды ISDN/DSL со скоростью 256 кбит/с. В данном случае рассматриваются только растровые изображения, поэтому все ссылки на изображения в тексте относятся к растровым изображениям, а не к векторной графике.
Проблемы и причины загрузки изображений
Вопрос первый: Загрузка слишком большого количества изображений при запуске страницы
фигура 1: Водопадная диаграмма новых розничных запросов на изображения
Анализ причины проблемы:Как показано на рисунке выше, при запуске страницы загружается около 49 изображений (конкретное количество изображений будет варьироваться в зависимости от данных, возвращаемых серверной частью), и эти запросы изображений выполняются почти одновременно. имя домена, поддерживается до изображений 6. Когда один запрос является одновременным, другие запросы будут помещены в очередь для ожидания или ожидания, а новые запросы в очереди не будут выдаваться до тех пор, пока не будет выполнен один из шести запросов. На приведенной выше каскадной диаграмме в зеленом поле маркера мы видим белые горизонтальные полосы разной длины, которые представляют собой время ожидания запрошенных ресурсов изображений для постановки в очередь.
Вопрос второй: Некоторые изображения слишком большие
фигура 2.Изображение загрузки изображения в верхней карусели
Анализ причины проблемы:Как показано на рисунке 1, красный прямоугольник — это изображение в карусельной рекламе в нижней части окна поиска Как видно из рисунка 2, изображение в основном занимает много времени вConent Download
сцена. Фаза загрузки заняла 13,50 с. А общее время запроса 13,78с. Причину этой проблемы также можно увидеть на рис. 1. Объем изображения76.2KB
,Изображение слишком большое, что напрямую приводит к долгой загрузке картинок.
Интерфейсные решения
Решение проблемы номер один
Поскольку на новой розничной домашней странице отображается большое количество изображений, фактически среди примерно 49 изображений большинство изображений не требуются для первого экрана, поэтому вы можете отложить загрузку изображений, которые не требуются для первого экрана. , и отдать приоритет загрузке картинок, необходимых для первого экрана. здесьвыше сгибаЗначение , относится к области внутри окна экрана при первом открытии новой домашней страницы магазина.
Чтобы определить, является ли изображение изображением в папке, первое, что приходит на ум, — это получить информацию о положении изображения с помощью метода getBoundingClientRect, чтобы определить, находится ли оно на первом экране.viewport
внутренний. Возможные коды следующие:
const inViewport = (el) => {
const rect = el.getBoundingClientRect()
return rect.top > 0
&& rect.bottom < window.innerHeight
&& rect.left > 0
&& rect.right < window.innerWidth
}
Однако в проекте мы не использовали эту схему, чтобы судить о том, находится ли он на первом экране, потому что только когда DOM-элемент вставляется в DOM-дерево, а страница переупорядочивается и перерисовывается, мы можем узнать, находится ли элемент находится на сгибе. на сгибе. В проекте мы использовалиv-imgИнструкция (новый розничный проект использует эту инструкцию для загрузки изображения и преобразования хэша в URL-адрес. Проект был открытым исходным кодом, и вы можете использовать его, если он соответствует вашим потребностям), который содержит две функции ловушки в инструкции Vue.bind
а такжеinserted
. Официальный сайт объясняет эти две функции хука следующим образом:
-
bind
: Вызывается только один раз, когда директива впервые привязывается к элементу. Здесь можно выполнить одноразовые настройки инициализации. -
inserted
: вызывается, когда связанный элемент вставляется в родительский узел (гарантируется существование только родительского узла, но не обязательно вставленного в документ).
Как видно из приведенного выше пояснения, мы можем только получить позицию элемента во вставленной функции хука и определить, находится ли он на первом экране. В новом розничном проекте, после авторского теста, разница во времени срабатывания между этими двумя функциями хука составляет около 200 мс, поэтому, если изображение загружается во вставленной функции хука, это будет примерно на 200 мс позже, чем в функции связывания хука. Сетевая среда 4G. В этих обстоятельствах 200 мс достаточно для загрузки многих изображений, поэтому мы, наконец, отказались от решения загрузки изображения выше сгиба во вставленной функции ловушки.
Как узнать, находится ли элемент выше сгиба, если он не вставлен в дерево DOM и не отрендерен?
<img v-img="{ hash: 'xxx', defer: true }">
В проекте используется относительно глупый способ определения того, какие картинки находятся вверху страницы: определяется макет новой розничной страницы: ниже столбца рекламы карусели — столбец продвижения, а затем — список магазинов. эти компоненты также относительно фиксированы, поэтому мы фактически заранее знаем, находятся ли эти компоненты на первом экране. Поэтому в реальном использованииv-imgкоманда, передавdefer
Элементы конфигурации, чтобы сообщить v-img, какие изображения должны быть загружены заранее, а какие изображения должны быть загружены после загрузки изображений, загруженных заранее. то что мы можем
Изображения, загружаемые первыми, загружаются в функцию ловушки привязки. Например, изображения компонентов карусели, изображения рекламных компонентов и изображения дисплея в первых двух магазинах должны быть загружены в первую очередь, а другие изображения должны быть загружены после того, как первое изображение экрана будет полностью загружено, прежде чем запрашивать загрузку. Фактический код реализации выглядит следующим образом:
const promises = [] // 用来存储优先加载的图片
Vue.directive('img', {
bind(el, binding, vnode) {
// ...
const { defer } = binding.value
// ...
if (!defer) {
promises.push(update(el, binding, vnode))
}
},
inserted(el, binding, vnode) {
const { defer } = binding.value
if (!defer) return
if (inViewport(el)) {
promises.push(update(el, binding, vnode))
} else {
Vue.nextTick(() => {
Promise.all(promises)
.then(() => {
promises.length = 0
update(el, binding, vnode)
})
.catch(() => {})
})
}
},
// ...
})
Во-первых, объявите массив обещаний для хранения изображения, которое будет загружено первым.Внутри функции ловушки привязки, если элемент конфигурации отсрочки имеет значение false, что указывает на то, что загрузка не отложена, тогда изображение загружается внутри функции ловушки привязки, и возвращенное обещание помещается в массив обещаний. Во вставленной функции ловушки для лениво загруженного изображения (defer имеет значение true), но оно находится на первом экране, оно также имеет приоритет для загрузки и будет загружено при вызове встроенной функции ловушки. Для изображений ниже сгиба и отложенной загрузки все изображения в массиве promises загружаются перед загрузкой. Конечно, в реальном коде также будет учитываться механизм отказоустойчивости, например, картинка выше не загружается или загружается слишком долго. Таким образом, мы можем настроить максимальное время ожидания.
Оптимизированная водопадная диаграмма загрузки изображений выглядит следующим образом:
изображение 3, Водопадная диаграмма с изображениями, загружаемыми по запросу.
Как показано на рисунке выше, изображение в красной рамке ниже не является изображением над сгибом, поэтому оно загружается лениво. Видно, что он загружается после загрузки всех вышеперечисленных картинок (включая картинку с самым длинным временем в красном поле выше). Это снижает потребление сети при загрузке первого экрана и повышает скорость загрузки изображения.
До и после оптимизации
По приведенной выше схеме оптимизации в заданном сетевом окружении (см. примечание в конце статьи) было проведено 5 параллельных экспериментов до и после оптимизации.清空缓存加载
, средние данные таковы:
Как видно из вышеприведенной таблицы,DOMContentLoaded
а такжеLoaded
Эталонного значения не так много.Время, необходимое для полного отображения первого экрана, по-прежнему определяется картинкой с самой медленной загрузкой (обычно картинка с наибольшим объемом), которая находится в таблице выше.Max_size_image
Из приведенной выше таблицы видно, что время загрузки изображения самого большого объема после оптимизации меньше, чем до оптимизации.5.74s. Ускорить весь41.41%. Изменение скорости загрузки самого медленного изображения также отражает изменение времени над сгибом.
Конечно, вышеприведенные данные не могут в полной мере отражать онлайн-сцену, ведь время проведения теста и серверные данные отличаются. Мы также не можем выполнять одновременный сбор данных до и после оптимизации в один и тот же момент времени и в одной и той же сетевой среде.
Есть несколько последующих решений для первой проблемы:
- В протоколах HTTP/1.0 и HTTP/1.1, поскольку Chrome поддерживает отправку только 6 одновременных запросов в одном и том же домене одновременно, можно выполнить сегментацию доменного имени, чтобы увеличить количество одновременных запросов, или протокол HTTP/2 может быть использовал.
Решение проблемы два
Изображение слишком большая, ведущая к длительной времени скачивания.Используйте как можно меньшее изображение, не жертвуя четкостью. Размер изображения определяется двумя факторами: общим количеством пикселей в изображении и количеством байтов, необходимых для кодирования единичного пикселя. Следовательно, размер файла изображения равен общему количеству пикселей в изображении, умноженному на количество байтов, необходимых для кодирования единичного пикселя, что соответствует следующему уравнению:
FileSize = Total Number Pixels * Bytes of Encode single Pixels
Например:
один100px * 100px
пиксельное изображение, содержащее100 * 100 = 10000
пикселей, и каждый пиксель проходит черезRGBA
значения цвета сохраняются,R\G\B\A
Каждый цветовой канал имеет 0~255 значений, что составляет 2^8 = 256. Ровно 8 бит 1 байт. Каждый пиксель имеет четыре цветовых канала, и каждый пиксель требует 4 байта. Итак, объем изображения:10000 * 4bytes = 40000bytes = 39KB
.
Обладая вышеуказанными базовыми знаниями, мы знаем, как оптимизировать картинку, не более чем в двух направлениях:
- Один из них — уменьшить количество байтов, необходимых для единичного пикселя.
- С другой стороны, уменьшение общего количества пикселей в изображении
оптимизация единичных пикселей: Оптимизация единичного пикселя также имеет два направления: одно — удалить некоторые пиксельные данные «с потерями», а другое — выполнить некоторое сжатие пикселей изображения «без потерь». Как и в приведенном выше примере,RGBA
Цветовые значения могут представлять256^4
цвет, который является большим числом, часто нам не нужно так много цветовых значений, поэтому можем ли мы уменьшить разнообразие цветов в образце? Это уменьшает количество байтов, представляющих единичный пиксель. Сжатие «без потерь» предназначено для максимально возможного уменьшения объема хранения изображений при условии сохранения данных пикселей без изменений с помощью некоторых алгоритмов. Например, пиксель на изображении очень близок к окружающим его пикселям, таким как изображение голубого неба, поэтому мы можем сохранить разницу между значениями цвета двух пикселей (конечно, реальный алгоритм может не учитывать только два пикселя) Может и больше точек), что не только обеспечивает "без потерь" пиксельных данных, но и уменьшает объем хранилища. Однако это также увеличивает накладные расходы на декомпрессию изображений.
Для оптимизации единичного пикселя выводятся различные форматы изображения.jpeg
,png
,gif
,webp
. Разные форматы изображений имеют свои алгоритмы уменьшения объема на пиксель. Они также имеют свои преимущества и недостатки, такие какjpeg
а такжеpng
Анимационные эффекты не поддерживаются,jpeg
Изображение имеет небольшой размер, но не поддерживает прозрачность и т. д. Таким образом, стратегия проекта при выборе формата изображения заключается в выборе наименьшего формата изображения, исходя из собственных потребностей.Новый розничный проект был использован единообразно.WebP
формат иjpeg
По сравнению с форматом его объем на 30% меньше, а также поддерживается анимация и прозрачность.
Общее количество пикселей изображения оптимизировано:
Рисунок 4: Сравнение размера загружаемого изображения и фактического размера рендеринга.
Изображение выше является одним из изображений, отображаемых в карусели на странице новой розничной категории после загрузки симулятора iPhone 6 в браузере Chrome.750 * 188
пикселей, но реальный размер изображения1440 * 360
Пиксели, то есть такая большая картинка нам вообще не нужна.Большие картинки не только увеличивают время загрузки картинки (данные будут пояснены позже), но и увеличивают нагрузку на ЦП из-за необходимости уменьшить размер изображения.
Как было сказано выше, в проекте мы используемv-img
команда для загрузки необходимых изображений в проект.Если мы можем загрузить изображения разных размеров (разное общее количество пикселей) в соответствии с размером устройства, то есть исходя из предпосылки обеспечения четкости изображений, попробуйте использовать маленькие картинки, проблема будет решена. В проекте мы используем сервис изображений Qiniu,Фотосервис ЦиньюОн предоставляет функции обработки изображений, такие как преобразование формата изображения и обрезка по размеру. просто нужноv-img
Команда добавляет конфигурацию ширины и высоты изображения, поэтому можем ли мы загружать изображения разных размеров для разных устройств?
Используем в проектеlib-flexibleадаптироваться к различным мобильным устройствам,lib-flexible
Библиотека добавляет два атрибута к элементу html нашей страницы,data-dpr
а такжеstyle
. Здесь мы в основном будем использовать стили в стилеfont-size
значение, которое составляет ровно одну десятую ширины html-элемента в пределах определенного диапазона устройств (о конкретных принципах см.:Использование Flexible для реализации терминальной адаптации страниц H5 Taobao), что означает, что мы можем примерно получить ширину устройства через атрибут стиля. В то же время эскиз дизайна разработан на основе iPhone6, то есть проект дизайна представляет собой чертеж дизайна шириной 750 пикселей, так что размер изображения в чертеже дизайна может быть преобразован в размер изображения, необходимый для другие устройства.
Например:
Изображение шириной 200 пикселей в черновике соответствует ширине 750 пикселей на устройстве iPhone 6. Мы рассчитываем ширину iPhone6 plus как 1242px через атрибут стиля элемента html. Это также позволит рассчитать необходимый размер изображения для iPhone 6 Plus. Расчет следующий:
200 * 1242 / 750 = 331.2px
Код реализации выглядит следующим образом:
const resize = (size) => {
let viewWidth
const dpr = window.devicePixelRatio
const html = document.documentElement
const dataDpr = html.getAttribute('data-dpr')
const ratio = dataDpr ? (dpr / dataDpr) : dpr
try {
viewWidth = +(html.getAttribute('style').match(/(\d+)/) || [])[1]
} catch(e) {
const w = html.offsetWidth
if (w / dpr > 540) {
viewWidth = 540 * dpr / 10
} else {
viewWidth = w / 10
}
}
viewWidth = viewWidth * ratio
if (Number(viewWidth) >= 0 && typeof viewWidth === 'number') {
return (size * viewWidth) / 75 // 75 is the 1/10 iphone6 deivce width pixel
} else {
return size
}
}
Вышеупомянутый метод изменения размера используется для преобразования настроенных значений ширины и высоты в фактический требуемый размер изображения, то есть параметр размера — это размер в проекте дизайна iPhone 6, а возвращаемое значение изменения размера — это размер. требуется текущему устройству.Этот размер настраивается в параметрах сервера изображений, чтобы мы могли получить изображение, обрезанное устройством.
Сравнение до и после оптимизации, на основе вышеизложенного мы провели эксперименты на разных симуляторах мобильных терминалов в Chrome, и сделали статистику по загрузке самого большого рекламного изображения на новой странице розничной категории на разных устройствах (очистить кеш и загрузить три раза параллельно), зачем выбирать самое большое изображение, как упоминалось выше, оно определяет время, необходимое для отображения первого экрана.
В приведенной выше таблице, за исключением неоптимизированной загрузки данных в последней строке, размер экрана устройства постепенно увеличивается сверху вниз, а также увеличивается размер загружаемого изображения с 23,2 кб до 65,5 кб. Время загрузки и время загрузки также увеличиваются с увеличением размера изображения.Линейный график ниже может лучше отражать положительную корреляцию между размером изображения, временем загрузки и временем загрузки. TTFB (время, необходимое от отправки запроса до получения первого байта) не имеет очевидной положительной корреляции с размером изображения, и может быть небольшая разница во времени, требуемом сервером изображений для обрезки изображений разных размеров.
Рисунок 5: При загрузке одного и того же изображения на разных устройствах полилиния меняется в размере файла, времени загрузки и скачивания.
На линейном графике выше также видно, что эффект особенно заметен для устройств с маленьким экраном: без оптимизации загрузка изображений в iPhone5 занимает 14,85 с, но после оптимизации время загрузки сокращается до 3,90 с. Время загрузки сократилось73.73%. А для большого экрана iPhone6 plus тоже есть26.00%Оптимизация времени.
Конечно, приведенные выше данные основаны на256 kbps ISDN/DSL
В низкоскоростной сетевой среде время загрузки изображения в основном определяется временем загрузки, поэтому за счет оптимизации объема изображения можно добиться хорошего эффекта. существует4G
(симуляция Чарльза), эффект оптимизации в iPhone5 будет несколько обесценен, а время загрузки будет сокращено.69.15%. На самом деле легко предположить, что в высокоскоростной сетевой среде влияние TTFB на время загрузки будет больше, чем в низкоскоростной сетевой среде.
окончательное резюме
Приведенные выше результаты исследований и данных показывают, что стратегия оптимизации для медленной загрузки новых изображений розничной торговли:
- Сначала загружается верхнее изображение, а нефальцованное изображение загружается после того, как верхнее изображение полностью загружено.
- Большинство изображений, особенно изображения в рекламных роликах, обрезаются в соответствии с размером устройства, чтобы уменьшить размер изображений, снизить нагрузку на сеть и увеличить скорость загрузки.
В этой статье не слишком подробно обсуждаются детали реализации кода, а основное внимание уделяется анализу причин медленной загрузки картинок и анализу данных сравнения эффектов до и после оптимизации.Если вы хотите увидеть больше детали кода, пожалуйста, переместитеvue-img.