Схема оптимизации загрузки изображений веб-страницы

JavaScript
Схема оптимизации загрузки изображений веб-страницы

Новые розничные товары в приложении 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.