Геймплей на экране скелета, о котором вы, возможно, не знаете🐶

внешний интерфейс DOM
Геймплей на экране скелета, о котором вы, возможно, не знаете🐶

〇 Предисловие

Это вторая передовая статья основной статьи, созданной автором после того, как компания обновила структуру деятельности.Учитывая, что эта статья является относительно независимой, она извлекается и пишется отдельно. Сестры и братья»,Геймплей с динамическими компонентами, о котором вы могли не знать 🍉".

Может быть, текст "Извините". Если вы знаете большого парня, не входите. Нет, нет, пожалуйста, жалуйтесь, делайте кирпич, Руи Сибай.

Слава богу Хао за вопрос 😂, не вините ssh, вините меня.

image.png

В этой статье могут быть некоторые недочеты, надеюсь, вы сделаете еще замечания и предложения, спасибо 😘.

〇 Фон

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

image.png

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

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

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

image.png

Как сократить время белого экрана?

Это сделано для того, чтобы пользователи могли быстрее видеть не «белые», такие как цвет фона фона, фоновое изображение, изображение ключевой части и т. д., которые могут быть связаны с ним.

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

〇 Реализация «схемы скелета»

Скелетный экран в основном обрисовывает структуру DOM с помощью линий, когда подробные элементы страницы не отображаются. Для страницы маркетинговой активности C-стороны нет стандартного скелета, и каждая активность имеет свою структуру, так что же нам делать?

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

image.png

Реализовать идеи

Глядя на действие по открытию красных конвертов, мы обнаружим, что контент, на который обращают внимание пользователи, — это «красные конверты» и цвет фона на картинке.

image.png

Мы должны сделать все возможное, чтобы изображение красного конверта "снос" отображалось быстрее.

Ниже приведен скриншот этого действия, через Chrome Dev Tools -> Network -> Disable Cache -> Fast 3G (4G, WIFI слишком быстр для наблюдения) -> right ⚙️ -> Capture ScreenShots. открыть. Вы можете просматривать кадр за кадром.

Наша цель — сделать ключевые кадры, кадр 1,44 с в зеленой рамке на рисунке ниже, можно отобразить раньше.

image.png

Как сформировать такую ​​рамку из ключевых картинок🤔? Естественно думать о статической странице. Это не что иное, как визуализация с помощью HTML, CSS и изображений.

image.png

Следовательно, необходимо предоставить структуру DOM, предоставить CSS, предоставить изображения и сгенерировать «статическую скелетную диаграмму».

image.png

Вышеупомянутое является обычной HTML-разработкой.

🤔️ Но мы не разрабатываем через чистый HTML, как нам получить DOM-структуру Vue-страницы?

Здесь у учащихся могут возникнуть вопросы, зачем нужно брать DOM-структуру Vue отдельно.

Обычно мы монтируем проект Vue под корневым узлом, например #app.

<html>
  <head></head>
  <body>
    <div id="app"></div>
    <script src="/cdn/xxx/vue.js"></script>
  </body>
</html>

Смонтировав экземпляр Vue в #app.

// index.js
import Entry from './Entry.vue'

new Vue({
  render: h => h(Entry)
}).$mount('#app')

Затем идет структура DOM (шаблон), соответствующая реальному компоненту.

// Entry.vue
<template>
  <div class="entry">
    <img src="/cdn/xx/image.png"/>
    <button class="btn" type="button">请点击</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
    }
  }
}
</script>

Из приведенного выше видно, что DOM-структура Vue на самом деле скрыта в файле .vue, и до того, как мы инициализируем и визуализируем Vue, мы можем получить только div #app.

Поэтому нам нужно найти способ получить структуру DOM в компоненте Vue. Как получить его?

image.png

Предварительная визуализация DOM

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

image.png

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

Здесь мы используем его, чтобы помочь нам перехватить структуру DOM Vue. Если мы используем puppetter для перехвата DOM, нам нужно будет сделать несколько шагов, запустить соответствующую страницу в безголовом браузере, а затем дождаться, пока страница отобразит компонент Vue.После завершения рендеринга перехватите структуру DOM под соответствующее #app и сохраните его.

Поскольку шаги несложные, но для этого потребуется много кода, на самом деле в сообществе уже есть большие ребята, которые помогут нам интегрировать эти возможности.prerender-spa-plugin, Это оно.

image.png

Используя prerender-spa-plugin, можно легко получить структуру DOM.Его принцип заключается в том, чтобы сначала запустить безголовый браузер, затем выполнить соответствующую маршрутизацию приложения и перехватить структуру DOM на отображаемой странице.

Конкретное использование prerender-spa-plugin здесь подробно обсуждаться не будет, вы можете обратиться к официальной документации.

cheerioЭто инструмент, который помогает нам получать контент, см. официальное объяснение.

Быстрая и гибкая реализация базовой реализации jQuery, разработанная специально для сервера.

Чтобы получить структуру DOM страницы Vue, вам нужно сделать это в два этапа.

  1. Сначала выполните предварительный рендеринг сборки и выведите ключевую структуру DOM страницы Vue, полученную в результате предварительного рендеринга.
  2. Затем выполните сборку в обычном режиме и вставьте полученную структуру DOM в исходный DOM страницы.

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

image.png

Ниже приведена конфигурация предварительного рендеринга для веб-пакета в сборке предварительного рендеринга.

// 预渲染构建的配置

{
  plugins: [
    // 生成vue dom骨架
    new PrerenderSPAPlugin({
      // 原文件地址
      staticDir: path.join(__dirname, config.localDir),
      // 构建生成地址
      outputDir: path.join(__dirname, config.prerenderPath),
      routes: [ '/' ],
      // 获取上下文
      postProcess (context) {
        // 获取编译后的html内容
        const html = context.html
				// 使用cheerio选择器
        const $ = cheerio.load(html)
        // 预渲染删除apple(一般C端页面都有个苹果免责协议,在预渲染的页面是多余的)
        $('#apple').remove()
        // 截取需要的html片段
        const contentHtml = '<div class="app">' + $('.app').html() + '</div>'
        // 删除掉一些首屏无关的image图片
        context.html = contentHtml.replace(/<img[^>]*>/gi, '')
				// 匹配每个标签里的style里的内容
        context.html = context.html.replace(/style="[^"]*"/g, function (matched) {
          // 如果符合以下布局属性,则保留,这里没考虑margin、padding等
          const reg = /(width|height|left|top|bottom|right):[^rem]*rem;/g
          const result = matched.match(reg)
          if (result) return 'style="' + result.join('') + '"'
          return ''
        })
        
        // 输出处理好的预渲染内容
        return context
      }
    })]
}

После того, как предварительный рендеринг построен, мы получаем DOM-структуру страницы Vue и начинаем официальное построение.

Формальная сборка

image.png

Здесь мы сами пишем плагин для Webpack, как писать плагин для Webpack здесь повторяться не будем. Основная функция — вставить предварительно отрендеренный DOM в официальный DOM.

// 正式构建,利用插件的能力

const path = require('path')
const fs = require('fs')

// 命名插件,也可以直接使用class定义,不是重点
function VueDomPrerenderPlugin (options) {
  this._options = options
}

VueDomPrerenderPlugin.prototype.apply = function (compiler) {
  const self = this
  compiler.hooks.compilation.tap('VueDomPrerenderPlugin', (compilation) => {
    // 通过html-webpack-plugin的hook
    compilation.plugin(
      'html-webpack-plugin-after-html-processing',
      (data, cb) => {
        // 找到预渲染输出的文件
        const prerenderFile = path.join(self._options.preoutDir, 'index.html')

        // 把预渲染生成的DOM,插入到正式DOM中。
        let htmlContent = data.html.replace('<div id="app"></div>', (matched) => {
          const prerenderHtml = fs.readFileSync(prerenderFile, 'utf8')
          return '<div id="app" data-server-render="true">' + prerenderHtml + '</div>'
        })
      }
    )
  })
}

module.exports = VueDomPrerenderPlugin

Но теперь он статичен, а картинки и цвета фона на странице фиксированы.Как можно динамически задавать картинки, цвета фона и т.д.?

image.png

Динамически устанавливаемые данные

image.png

HTML и CSS можно использовать только как статические страницы, но JavaScript может, а JS может получать данные и устанавливать их в соответствии с данными, поэтому наши страницы не являются жестко запрограммированными изображениями и цветами.

Сначала получите соответствующие данные изображения и цвета через JS, затем найдите соответствующий заполнитель изображения в структуре DOM и т. д. и установите изображение с помощью JS. Здесь есть три шага.

// H5页面中的代码

let color = window.CFG.color
let bgImage = window.CFG.bgImage
let bgColor = window.CFG.bgColor
// 类似的还有其他数据...

let $text = document.querySelector('.text')
let $bg = document.querySelector('.bg')
// 类似的还有很多...

$text.style.color = color
$bg.style.backgroundImage = 'url(' + bgImage + ')'
$bg.style.backgroundColor = bgColor
// 类似的还有很多...

🤔️ Из-за вышеупомянутого императивного метода JS читабельность настроек стилей плохая, и у нас слишком много шаблонного кода, который относительно навязчив для бизнеса и недружелюбен к разработке. Как это сделать?

image.png

уменьшить дублирующийся код

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

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

грубый процесс.

image.png

определить шаблон

image.png

Мы подумали о том, можем ли мы использовать возможность шаблонов для предоставления файла типа .tcss, который является файлом, подобным CSS. Вы можете видеть, что мы предоставляем возможности настройки переменных через **{{ }}**.

image.png

image.png

Разобрать шаблон

image.png

Итак, как разобрать такой шаблон, мы передаем возможности узла и регулярных выражений. Вам нужно предоставить часть логики кода, сначала прочитать файл .tcss, а затем заменить шаблон реальным исполняемым кодом.

// node脚本中的代码
// 解析preload.tcss,输出preloadCss、preloadImages

// 某个活动下
const BASE_FOLDER = `./src/pages/activity`
// 上述文件.tcss所在地址
const cssPath = path.join(BASE_FOLDER, 'preload.tcss')
// 获取文件的字符串
const data = fs.readFileSync(cssPath).toString()

// 匹配字符串的开始
let start = 0
// 记录预加载的图片
const preloadImages = []

let preloadCss = data.replace(/{{(\S+)}}/g, function (matched, pattern, offset, string) {
  // 当前匹配到的字段的偏移量
  let end = offset

  // 截取非空字符串
  const substring = string.substring(start, end)

  // 只有image类型的才会存到预加载数组里
  if (substring.indexOf('url') !== -1) {
    preloadImages.push(`get('${pattern}')`)
  }

  // 上一次的终点为这次的起点
  start = end

  // 把匹配到的例如image、color进行包装
  return `' + get('${pattern}') + '`
})

// 统一成\n
preloadCss = preloadCss.replace(/(\r|\n|\r\n)/g, function (matched) {
  return `'\n+'`
})

Примерный код приведен выше, который выведет список предварительно загруженных изображений — preloadImages и JS-фрагмент стиля предварительной загрузки Style — preloadCss.

Чтобы сгенерировать JS-фрагмент стиля, вы можете задаться вопросом, как генерируется такой фрагмент кода JS, потому что мы сначала предварительно создали код JS, который может «генерировать CSS» локально через скрипт узла, и, наконец, этот код является страницей. рендеринг время запуска. Почему не чистый CSS, ведь нам нужно динамически получать значения свойств (изображение, цвет и т.д.).

preloadCss примерно такой, как показано на рисунке ниже.

image.png

PreloadImages примерно такие, как показано ниже.

image.png

image.png

Код производственного материала (изображение, CSS)

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

image.png

После получения preloadImages и preloadCss мы вызываем общедоступные методы для загрузки изображений и генерации фрагментов стилей.

// node脚本中的代码

const TARGET_PATH = './node_modules/.cache/preload-image/'

const outputFilePath = path.join(TARGET_PATH, 'index.js')

if (!fs.existsSync(TARGET_PATH)) {
  fs.mkdirSync(TARGET_PATH, { recursive: true })
}

const preloadCode = `
;(function(win) {
  var preloadImages = [${preloadImages.join(',')}];

  preloadImage(preloadImages);

  var styles = '${preloadCss}';

  addPreloadStyle(styles);
})(window);
`

fs.writeFileSync(outputFilePath, preloadCode)

Приведенный выше код объединяется в строку строк, которые в конечном итоге будут встроены в HTML-страницу и будут выполняться при отображении страницы.

Таким образом, мы завершили предзагруженные материалы: подготовка картинок и стилей. Далее нужно нанести препарат на страницу.

image.png

Встроенный код на страницу

image.png

Набор изображений для предварительной загрузки, стиль JS, встроенный способ проникнуть в HTML.

<html>
  <head>
	<script src="./node_modules/.cache/preload-image/index.js?__inline"></script>
  </head>
</html>

Как видите, что делает __inline?Его эффект заключается в том, чтобы встроить исходящий JS в HTML.

<html>
  <head>
    <script>
      function preloadImage (arr) {
        for (let i = 0; i < arr.length; i++) {
          const images = []
          images[i] = new Image()
          images[i].src = arr[i]
        }
      }

      function addPreloadStyle (styles) {
        const css = document.createElement('style')
        css.type = 'text/css'

        if (css.styleSheet) {
          css.styleSheet.cssText = styles
        } else {
          css.appendChild(document.createTextNode(styles))
        }

        document.getElementsByTagName('head')[0].appendChild(css)
      }
    </script>
		<script>
      !function(win){
        var preloadImages = [
          get("bgImage"),
          // 省略了...
        ];
        preloadImage(preloadImages);

        var preloadCss = '.tac-app {' +  
            'background-image: url("'+ get("bgImage")+'");' +  
            'background-color: '+ get("bgColor")+';' +
            '}'
        addPreloadStyle(preloadCss)
      (window);
    </script>
  </head>
</html>

image.png

«Благополучие: плагин веб-пакета для функции __inline»

Что касается вышеизложенного, как реализована функция __inline, вы можете взглянуть на метод написания этого плагина веб-пакета.

/*
 * script标签中含有?__inline标识的Js会被内联到HTML。
 */
const fs = require('fs')

const getScriptAbsolutePath = (matched, reg) => {
  const result = matched.match(reg)
  const relativePath = result && result[1]

  return relativePath
}

class ScriptInlinePlugin {
  apply (compiler) {
    compiler.hooks.compilation.tap('ScriptInlinePlugin', (compilation) => {
      // 由于vuecli3使用的webpack-html-plugin是3.2版本,所以暂时不能使用tap形式。
      compilation.plugin(
        'html-webpack-plugin-after-html-processing',
        (data) => {
          // 读取目标模版
          let htmlContent = data.html

          // 匹配script的reg
          const jsReg = /<script[^<]*?src="?[^<]*?\?__inline"?.*?>.*?<\/script>/gmi

          // 匹配script片段
          htmlContent = htmlContent.replace(jsReg, (matched) => {
            // 获取script绝对地址
            const absolutePath = getScriptAbsolutePath(matched, /src="?(.*)\?__inline/)

            // 获取script对应地址的内容
            const jsContent = fs.readFileSync(absolutePath, 'utf-8')

            return `<script type="text/javascript">${jsContent}</script>`
          })

          data.html = htmlContent
        }
      )
    })
  }
}

module.exports = ScriptInlinePlugin

Основные функции уже доступны, но после некоторого времени использования я обнаружил некоторые проблемы.

Опыт Соображения

Мы обнаружили, что функция реализована, но не очень удобна для разработки.

Шаги анализа

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

  1. Заполнитель предварительно загруженного изображения устанавливается в vue, чтобы можно было связать предварительно загруженное изображение.
<template>
  <div :class="$style.app">
    <div :class="$style.button">
    </div>
    <div :class="$style.cat">
    </div>
  </div>
</template>

<style lang="less" module>
// 预渲染使用的全局class占位符
:global {
  .app {}
  .button {}
  .cat {}
}
</style>
  1. Вам нужно знать, какие переменные возвращаются внутренним интерфейсом, а затем установить их в соответствующий файл .tcss.
// backgroundColor
// backgroundImage

// buttonImage

// catImage
  1. tcss устанавливает соответствующий стиль предварительной загрузки для записи
.app {
  background-image: url("{{backgroundImage}}");
}

.button {
  background-image: url("{{buttonImage}}");
}

.cat {
  background-image: url("{{catImage}}");
}

image.png

Умственные затраты на развитие одноклассников все еще относительно велики, и ему нужно слишком много заботиться.

Предварительная информация

На следующем рисунке показан основной поток действия.

image.png

Забудьте о деталях и сосредоточьтесь на потоке ключевых действий.

  1. Пользователь заходит на активную страницу, и сервер начинает рендеринг;
  2. Разработка деятельности обеспечивает код деятельности, развитие инфраструктуры обеспечивает общедоступный код;
  3. Операция по деятельности Настройка действий через платформу управления операциями;
  4. Сервер запускает объединение шаблонов и получает код и конфигурацию из базы данных для объединения;
  5. Браузер представляет активную страницу.

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

Таким образом, мы можем подтвердить, какие изображения могут быть предварительно загружены при настройке платформы управления операциями.

Конфигурировать вместо кодирования

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

image.png

Возьмите все выбранные изображения в виде списка и передайте его в бэкэнд SSR.Поскольку наш бэкенд Java отображается как шаблон, используется шаблон Velocity.

// 通过Velocity循环渲染。
#foreach( $key in $preloadImageList )
    <link rel="preload" as="image" href="$preloadImageList.get($key)">
#end

Таким образом, мы освобождаем передовых студентов от бремени кодирования и предварительной загрузки.

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

〇 Более быстрая загрузка изображений

Примечание ⚠️, для просмотра сети ниже сначала выполните следующие действия: Chrome Dev Tools -> Network -> Disable Cache -> Fast 3G.

Порядок загрузки ресурсов

В приведенном выше примере мы используем новый метод Image для загрузки изображения, но будут проблемы.

новая загрузка изображения

Давайте разберемся в этой проблеме на примере. На этой странице необходимо загрузить 3 изображения, 2 файла CSS и 6 файлов JS.

<!DOCTYPE html>
<html>
<head>
    <script>
        function preloadImage(arr) {
            for (let i = 0; i < arr.length; i++) {
                const images = []
                images[i] = new Image()
                images[i].src = arr[i]
            }
        }
        preloadImage(
            [
                'http://yun.tuisnake.com/tuia/dist/image/1.jpg',
                'http://yun.tuisnake.com/tuia/dist/image/2.png',
                'http://yun.tuisnake.com/tuia/dist/image/3.png'
            ])
    </script>
    <link rel="stylesheet"
			href="http://yun.tuisnake.com/tuia/dist/css/bootstrap1.css">
    <link rel="stylesheet"
			href="http://yun.tuisnake.com/tuia/dist/css/bootstrap2.css">
</head>

<body>
    <script src="http://yun.tuisnake.com/tuia/dist/js/vue1.js"></script>
    <script src="http://yun.tuisnake.com/tuia/dist/js/vue2.js"></script>
    <script src="http://yun.tuisnake.com/tuia/dist/js/vue3.js"></script>
    <script src="http://yun.tuisnake.com/tuia/dist/js/vue4.js"></script>
    <script src="http://yun.tuisnake.com/tuia/dist/js/vue5.js"></script>
    <script src="http://yun.tuisnake.com/tuia/dist/js/vue6.js"></script>
</body>
</html>

Мы обнаружили, что образ был загружен после того, как были загружены первые четыре файла JS. Но мы бы хотели, чтобы изображения можно было загрузить раньше.

image.png

Для студентов, которые не понимают приведенную выше картинку, вы можете прочитать ее.Timing breakdown phases explained

Почему это? Во-первых, в протоколе Http1.1 одновременно может быть открыто только 6 TCP-соединений под одним и тем же доменным именем, поэтому требуется организация очереди ресурсов.

Ресурсы имеют приоритет

Но этого кажется недостаточно для объяснения 🧐, продолжаем искать причину.

image.png

Мы обнаружили, что есть поле «Приоритет», а ресурс изображения — «Низкий».Похоже, что изображение имеет самый низкий приоритет в очереди.

image.png

Но для чего этот приоритет?

Подумайте об этом 🤔️Как наш браузер узнает, какие ресурсы скачивать первыми? Здесь не продается.

  1. В первую очередь необходимо четко классифицировать ресурсы браузера.
  2. Затем вычислить приоритет ресурса
  3. Наконец, загрузите последовательно в соответствии с приоритетом ресурса

Дальнейшее чтение можно найти здесь:Процесс загрузки ресурсов страницы браузера и оптимизация.

Таким образом, мы обнаружили, что браузер имеет приоритет загрузки ресурсов, например, CSS, HTML, JS и т. д. являются всеми основными ресурсами, поэтому приоритет является наивысшим, а изображения, видео и аудио не являются основными ресурсами, а приоритет равен относительно низко. Обычно, когда последний сталкивается с первым, ему необходимо «уступить дорогу» и перейти в состояние ожидания.

приоритет изображения

image.png

Возвращаясь к этой статье, почему у нас низкий приоритет изображения, можно ли его улучшить? Итак, давайте кое-что узнаем.

Avoid chaining critical requestsупомянулОтчет о приоритетах браузера(Предоставлено Пэтом Минаном), показывающим, как Chrome с ядром Blink, начиная с Chrome 46 и выше, отдает приоритет различным ресурсам.

Следующая картинка — это приоритет загрузки Chrome в статье выше, вы можете его наблюдать.

PS: Эта картинка 2015 года, и поведение браузеров сейчас может быть другим. Я надеюсь, что есть студенты, которые знают обновленную версию, пожалуйста, оставьте сообщение, спасибо.

image.png

Мы видим, что Image имеет два типа приоритета, один находится внутри представления — Image (в области просмотра), а другой вне представления — Image. Соответствует высокому и низкому приоритетам соответственно.

Мы также нашли подсказки по этому поводу в другой статье на сайте web.dev.Fast load timesв модулеPrioritize resourcesВведение в статью.

for example, an image that is part of the initial render is prioritized higher than an image that starts offscreen.

Загрузка в качестве фонового изображения

Так говорит теория, давайте проверим. Мы добавили стили, DOM и настройки фонового изображения ко всем трем изображениям, чтобы они существовали в представлении.

<!DOCTYPE html>
<html>
<head>
    <style>
        .image1, .image2, .image3 {
          height: 300px;
          width: 400px;
        }
        .image1 {
          background-image: url('http://yun.tuisnake.com/tuia/dist/image/1.jpg');
        }
        .image2 {
          background-image: url('http://yun.tuisnake.com/tuia/dist/image/2.png');
        }
        .image3 {
          background-image: url('http://yun.tuisnake.com/tuia/dist/image/3.png');
        }
    </style>
    <!-- 利用bootstrap作为测试css,有2个 -->
    <link rel="stylesheet"
			href="http://yun.tuisnake.com/tuia/dist/css/bootstrap1.css">
    <link rel="stylesheet"
			href="http://yun.tuisnake.com/tuia/dist/css/bootstrap2.css">
</head>

<body>
    <div class="image1"></div>
    <div class="image2"></div>
    <div class="image3"></div>
    <!-- 利用vue作为测试js,有6个 -->
    <script src="http://yun.tuisnake.com/tuia/dist/js/vue1.js"></script>
    <script src="http://yun.tuisnake.com/tuia/dist/js/vue2.js"></script>
    <script src="http://yun.tuisnake.com/tuia/dist/js/vue3.js"></script>
    <script src="http://yun.tuisnake.com/tuia/dist/js/vue4.js"></script>
    <script src="http://yun.tuisnake.com/tuia/dist/js/vue5.js"></script>
    <script src="http://yun.tuisnake.com/tuia/dist/js/vue6.js"></script>
</body>
</html>

Результат показан ниже.

image.png

Судя по картинке выше, это правда, что приоритет картинки поднят до High, но она все равно грузится после js файла, почему так?

Изображение background-image, существующее в css background image, не начнет загружаться до тех пор, пока не будет загружена структура (после отображения всего содержимого веб-страницы); в то время как тег img в html является частью структуры (контента) веб-страницы и будет загружаться в процессе загрузки структуры load.

А что, если мы попытаемся использовать тег img напрямую?

image.png

Загрузка как вкладка

<!DOCTYPE html>
<html>
<head>
    <!-- 利用bootstrap作为测试css,有2个 -->
    <link rel="stylesheet"
			href="http://yun.tuisnake.com/tuia/dist/css/bootstrap1.css">
    <link rel="stylesheet"
			href="http://yun.tuisnake.com/tuia/dist/css/bootstrap2.css">
</head>

<body>
    <!-- 修改点 -->
 	  <img src="http://yun.tuisnake.com/tuia/dist/image/1.jpg"/>
    <img src="http://yun.tuisnake.com/tuia/dist/image/2.png"/>
    <!-- 利用vue作为测试js,有6个 -->
    <script src="http://yun.tuisnake.com/tuia/dist/js/vue1.js"></script>
    <script src="http://yun.tuisnake.com/tuia/dist/js/vue2.js"></script>
</body>
</html>

Видим, что картинка действительно загружается в первый раз.

image.png

Так ли это на самом деле, заранее ли загружается изображение, если оно в виде тега img?

Давайте попробуем еще одну DEMO, 2 файла CSS и 4 файла JS.

<!DOCTYPE html>
<html>
<head>
    <!-- 利用bootstrap作为测试css,有2个 -->
    <link rel="stylesheet"
			href="http://yun.tuisnake.com/tuia/dist/css/bootstrap1.css">
    <link rel="stylesheet"
			href="http://yun.tuisnake.com/tuia/dist/css/bootstrap2.css">
</head>

<body>
    <!-- 修改点 -->
 	  <img src="http://yun.tuisnake.com/tuia/dist/image/1.jpg"/>
    <img src="http://yun.tuisnake.com/tuia/dist/image/2.png"/>
    <!-- 利用vue作为测试js,有6个 -->
    <script src="http://yun.tuisnake.com/tuia/dist/js/vue1.js"></script>
    <script src="http://yun.tuisnake.com/tuia/dist/js/vue2.js"></script>
    <script src="http://yun.tuisnake.com/tuia/dist/js/vue3.js"></script>
    <script src="http://yun.tuisnake.com/tuia/dist/js/vue4.js"></script>
</body>
</html>

Давайте посмотрим на результаты.

image.png

Мы обнаружили, что два графических ресурса отстают. Вот почему а? ? ?

image.png

Вспоминая предзнаменование, которое я похоронил перед этим разделом, 2 CSS + 4 JS уже заполнили лимит в 6 запросов на доменное имя, и картина отстает.

Так почему же изображения не могут захватывать CSS и JS? Посмотрите еще раз на эту картинку.

image.png

Когда изображение инициализировано, приоритетом по умолчанию является Низкий, и только когда браузер отображает изображение, он вычисляет, следует ли упоминать изображение в представлении с высоким приоритетом. Вы видели что-нибудь, потому что CSS и Script будут иметь более высокий приоритет, чем изображение.

Загрузка изображений через image тоже не очень надежна, есть ли другой способ?

image.png

Приоритетная загрузка изображения

Давайте взглянем на один API, preload.

Способ 1: предварительная загрузка изображений

Также прочитайте эту статьюPreload, Prefetch And Priorities in ChromeПоймите, вот переведенная версия,Preload, Prefetch и их приоритетная оптимизация производительности в Chrome.

Приоритет изображения увеличен, но оно не обязательно загружается с первого раза. Как я могу принудительно увеличить порядок загрузки изображений?

  1. Три типа ресурсов, html, css и шрифт, имеют наивысший приоритет;
  2. Затем ресурс предварительной загрузки (черезпредварительная загрузка тега), скрипт, запрос xhr.
<!DOCTYPE html>
<html>
<head>
    <!-- 修改点 -->
    <link rel="preload" as="image" href="http://yun.tuisnake.com/tuia/dist/image/1.jpg">
    <link rel="preload" as="image" href="http://yun.tuisnake.com/tuia/dist/image/2.png">

    <!-- 利用bootstrap作为测试css,有2个 -->
    <link rel="stylesheet"
			href="http://yun.tuisnake.com/tuia/dist/css/bootstrap1.css">
    <link rel="stylesheet"
			href="http://yun.tuisnake.com/tuia/dist/css/bootstrap2.css">
</head>

<body>
    <!-- 利用vue作为测试js,有6个 -->
    <script src="http://yun.tuisnake.com/tuia/dist/js/vue1.js"></script>
    <script src="http://yun.tuisnake.com/tuia/dist/js/vue2.js"></script>
    <script src="http://yun.tuisnake.com/tuia/dist/js/vue3.js"></script>
    <script src="http://yun.tuisnake.com/tuia/dist/js/vue4.js"></script>
    <script src="http://yun.tuisnake.com/tuia/dist/js/vue5.js"></script>
    <script src="http://yun.tuisnake.com/tuia/dist/js/vue6.js"></script>
</body>
</html>

С помощью предварительной загрузки мы можем изменить порядок загрузки ресурсов браузера.

image.png

Как видно из изображения выше, наше изображение действительно загружается впервые.

image.png

Есть ли другой способ?

Способ 2: отдельное доменное имя изображения

Мы знаем, что http1.1 ограничен 6 ссылками под одним и тем же доменным именем, поэтому мы можем попробовать несколько доменных имен? Дайте изображению другое уникальное доменное имя.

<!DOCTYPE html>
<html>
<head>
    <script>
        function preloadImage(arr) {
            for (let i = 0; i < arr.length; i++) {
                const images = []
                images[i] = new Image()
                images[i].src = arr[i]
            }
        }
    </script>
    <!-- 测试图片3张 -->
    <script>
        preloadImage(
            [
                'https://yun.tuipink.com/tuia/dist/image/1.jpg',
                'https://yun.tuipink.com/tuia/dist/image/2.png',
                'https://yun.tuipink.com/tuia/dist/image/3.png'
            ])
    </script>
    <!-- 利用bootstrap作为测试css,有2个 -->
    <link rel="stylesheet"
			href="https://yun.tuisnake.com/tuia/dist/css/bootstrap1.css">
    <link rel="stylesheet"
			href="https://yun.tuisnake.com/tuia/dist/css/bootstrap2.css">
</head>

<body>
    <!-- 利用vue作为测试js,有6个 -->
    <script src="https://yun.tuisnake.com/tuia/dist/js/vue1.js"></script>
    <script src="https://yun.tuisnake.com/tuia/dist/js/vue2.js"></script>
    <script src="https://yun.tuisnake.com/tuia/dist/js/vue3.js"></script>
    <script src="https://yun.tuisnake.com/tuia/dist/js/vue4.js"></script>
    <script src="https://yun.tuisnake.com/tuia/dist/js/vue5.js"></script>
    <script src="https://yun.tuisnake.com/tuia/dist/js/vue6.js"></script>
</body>
</html>

Хорошо видно, что картинка тоже загружается в первый раз.

image.png

Выглядит тоже хорошо, не так ли, есть ли другой способ?

Способ 3: понизить приоритет других ресурсов

Благодаря таблице приоритетов мы знаем, что если JS загружается позже, изображение загружается раньше.

Сначала мы можем рассмотреть теги async и defer.

image.png

async vs defer attributes - Growing with the Web

Но я обнаружил, что async и defer не меняют порядок запросов js-файлов, они по-прежнему находятся перед изображением.

"асинхронный"

<!DOCTYPE html>
<html>
<head>
    <!-- 利用bootstrap作为测试css,有2个 -->
    <link rel="stylesheet"
			href="http://yun.tuisnake.com/tuia/dist/css/bootstrap1.css">
    <link rel="stylesheet"
			href="http://yun.tuisnake.com/tuia/dist/css/bootstrap2.css">
</head>

<body>
    <image src="http://yun.tuisnake.com/tuia/dist/image/1.jpg"></image>
    <image src="http://yun.tuisnake.com/tuia/dist/image/2.png"></image>
    <image src="http://yun.tuisnake.com/tuia/dist/image/3.png"></image>
    <!-- 利用vue作为测试js,有6个 -->
    <script async src="http://yun.tuisnake.com/tuia/dist/js/vue1.js"></script>
    <script async src="http://yun.tuisnake.com/tuia/dist/js/vue2.js"></script>
    <script async src="http://yun.tuisnake.com/tuia/dist/js/vue3.js"></script>
    <script async src="http://yun.tuisnake.com/tuia/dist/js/vue4.js"></script>
    <script async src="http://yun.tuisnake.com/tuia/dist/js/vue5.js"></script>
    <script async src="http://yun.tuisnake.com/tuia/dist/js/vue6.js"></script>
</body>
</html>

Изображение по-прежнему загружается последним.

image.png

"отложить"

<!DOCTYPE html>
<html>
<head>
    <!-- 利用bootstrap作为测试css,有2个 -->
    <link rel="stylesheet"
			href="http://yun.tuisnake.com/tuia/dist/css/bootstrap1.css">
    <link rel="stylesheet"
			href="http://yun.tuisnake.com/tuia/dist/css/bootstrap2.css">
</head>

<body>
    <image src="http://yun.tuisnake.com/tuia/dist/image/1.jpg"></image>
    <image src="http://yun.tuisnake.com/tuia/dist/image/2.png"></image>
    <image src="http://yun.tuisnake.com/tuia/dist/image/3.png"></image>
    <!-- 利用vue作为测试js,有6个 -->
    <script defer src="http://yun.tuisnake.com/tuia/dist/js/vue1.js"></script>
    <script defer src="http://yun.tuisnake.com/tuia/dist/js/vue2.js"></script>
    <script defer src="http://yun.tuisnake.com/tuia/dist/js/vue3.js"></script>
    <script defer src="http://yun.tuisnake.com/tuia/dist/js/vue4.js"></script>
    <script defer src="http://yun.tuisnake.com/tuia/dist/js/vue5.js"></script>
    <script defer src="http://yun.tuisnake.com/tuia/dist/js/vue6.js"></script>
</body>
</html>

Это тоже не работает, изображение все равно загружается последним.

image.png

Вышеуказанные два способа не работают, есть ли другой способ?

«JS-загрузчик»

Поскольку нативный вариант не годится, давайте использовать код JS для управления временем вставки скриптов и CSS.

<!DOCTYPE html>
<html>
<head>
    <!-- 利用bootstrap作为测试css,有2个 -->
    <link rel="stylesheet"
			href="https://yun.tuisnake.com/tuia/dist/css/bootstrap1.css">
    <link rel="stylesheet"
			href="https://yun.tuisnake.com/tuia/dist/css/bootstrap2.css">
</head>

<body>
    <!-- 修改点 -->
    <image src="https://yun.tuisnake.com/tuia/dist/image/1.jpg"></image>
    <image src="https://yun.tuisnake.com/tuia/dist/image/2.png"></image>
    <image src="https://yun.tuisnake.com/tuia/dist/image/3.png"></image>

    <script src="https://yun.tuisnake.com/tuia/dist/js/loader.js"></script>
    <script>
        Loader.async([
            'https://yun.tuisnake.com/tuia/dist/js/vue1.js', 
            'https://yun.tuisnake.com/tuia/dist/js/vue2.js',
            'https://yun.tuisnake.com/tuia/dist/js/vue3.js', 
            'https://yun.tuisnake.com/tuia/dist/js/vue4.js',
            'https://yun.tuisnake.com/tuia/dist/js/vue5.js', 
            'https://yun.tuisnake.com/tuia/dist/js/vue6.js'
        ])  
    </script>
</body>
</html>

Вы можете видеть, что очевидные изображения загружаются первыми.

image.png

Так много было сказано ранее о Http1.1, давайте теперь рассмотрим случай Http2.0.

Способ 4: HTTP2.0

Нам нужно включить Http2.0,Для доменного имени yun.tuiapple.com включен Http2.0.

<!DOCTYPE html>
<html>
<head>
    <script>
        function preloadImage(arr) {
            for (let i = 0; i < arr.length; i++) {
                const images = []
                images[i] = new Image()
                images[i].src = arr[i]
            }
        }
    </script>
    <!-- 测试图片3张 -->
    <script>
        preloadImage(
            [
                'https://yun.tuiapple.com/tuia/dist/image/1.jpg',
                'https://yun.tuiapple.com/tuia/dist/image/2.png',
                'https://yun.tuiapple.com/tuia/dist/image/3.png'
            ])
    </script>
    <!-- 利用bootstrap作为测试css,有2个 -->
    <link rel="stylesheet"
			href="https://yun.tuiapple.com/tuia/dist/css/bootstrap1.css">
    <link rel="stylesheet"
			href="https://yun.tuiapple.com/tuia/dist/css/bootstrap2.css">
</head>

<body>
    <!-- 利用vue作为测试js,有6个 -->
    <script src="https://yun.tuiapple.com/tuia/dist/js/vue1.js"></script>
    <script src="https://yun.tuiapple.com/tuia/dist/js/vue2.js"></script>
    <script src="https://yun.tuiapple.com/tuia/dist/js/vue3.js"></script>
    <script src="https://yun.tuiapple.com/tuia/dist/js/vue4.js"></script>
    <script src="https://yun.tuiapple.com/tuia/dist/js/vue5.js"></script>
    <script src="https://yun.tuiapple.com/tuia/dist/js/vue6.js"></script>
</body>
</html>

Мы обнаружили, что изображения загружаются почти одновременно с CSS и JS.

image.png

окончательный план

Поскольку наша бизнес-среда предназначена для подключения ко многим носителям, но некоторые носители не поддерживают Https, нам необходимо одновременно учитывать среду Http2.0 и Http1.0.

В случае поддержки Https мы используем схему Http2.0, в случае отсутствия поддержки Https используем предварительную загрузку ссылки в сочетании с одним доменным именем изображения. Метод 3 ограничивает метод внешней загрузки, который является более интрузивным и пока не будет рассматриваться.

Что касается предварительной загрузки, после нескольких лет разработки браузера совместимость не является большой проблемой, вы можете обратиться кcaniuse.

более быстрые фоновые изображения

Условно говоря, фоновое изображение все еще относительно велико, как его можно отобразить быстрее?

прогрессивный

Тип JPEG имеет прогрессивный JPEG, который позволяет избежать полностью белого экрана в плохих условиях сети.

6a0120a85dcdae970b0128776fcab6970c.gif

Progressive jpeg (прогрессивный jpeg) картинки и связанные с ними

компрессия

Мы также можем сжимать изображения в форматах JPEG и PNG. Мы сделали специальный сервис сжатия изображений, который будет представлен в следующих главах.

image.png

Та же картинка, сжатая webp, будет меньше.

тайник

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

image.png

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

в линию

Взгляните на это, вставив «маленькое изображение» base64.небольшая демонстрация, конкретная конструкция здесь повторяться не будет, но дается идея.

〇 Краткое резюме

Реализация похожа на каркасный экран.

  1. Заранее запустите страницу через безголовый браузер, чтобы получить текущую структуру DOM.
  2. Предоставляя css-подобный шаблон (когда разработчики кодируют, задают картинки, цвета и т. д. в шаблоне), сгенерируйте кусок js (с возможностью загрузки картинок и генерации css-фрагментов) через компиляцию и вставьте html-заголовок.
  3. В сочетании с динамически сгенерированным css во время выполнения, структурой DOM страницы, полученной заранее, и загруженными изображениями представлена ​​грубая «скелетная диаграмма».
  4. И, наконец, обсуждение загрузки изображений.

Или отвечу на начало, в этой статье могут быть какие-то недочеты, надеюсь вы сделаете еще замечания и предложения, спасибо 😘.

image.png

Эпилог

Просматривая предыдущие статьи автора с высокой похвалой, можно обнаружить неожиданные успехи!

😘Нравится + Комментарий + Ретвит 😘, создать оригинальную статью непросто, поощряйте написание новых статей

Расширенное чтение

Порядок загрузки ресурсов

Процесс загрузки ресурсов страницы браузера и оптимизация

Если вам интересно, вы можете проанализировать его с точки зрения исходного кода.

Посмотрите, как браузер загружает ресурсы из исходного кода Chrome Develop Paper

Если вам интересно узнать о приоритете JS, вы можете обратиться к

Приоритет загрузки JavaScript в Chrome | FENews.

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

Use Imagemin to compress images