Проблемы с производительностью, вызванные перекомпоновкой и перерисовкой

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

Пока reflow и repaint не написаны с мыслью, что в горах водятся тигры и предпочитают путешествовать по горам, эти два продукта вряд ли вызовут проблемы с производительностью. Однако возможности рендеринга мобильного терминала более чем сильно отличаются от терминала ПК.Небрежное переформатирование и перерисовка становятся «убийцей производительности» мобильного терминала. Следовательно, также необходимо понимать перекомпоновку и перерисовку.При рассмотрении производительности страницы анализ перекомпоновки и перерисовки также является отправной точкой.

что


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

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

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

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

Как вызвать


reflow

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

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

  • Свойства позиционирования и плавающиеСвязанные свойства: top, position, float и т. д.

  • изменение внутри узластруктура текстаТакже вызывает перекомпоновку: text-align, overflow, font-size, line-height, vertival-align и т. д.

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

  • изменить размер окна
  • изменения таблицы стилей
  • Изменения содержимого элемента, особенно элементов управления вводом
  • дом операция
  • css активация псевдокласса
  • Вычислить offsetWidth, offsetHeight, clientWidth, clientHeight, width, height, scrollTop, scrollHeight элемента

repaint

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

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

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

умный браузер


Представьте себе такой сценарий, нам нужно постоянно изменять позицию или содержимое узла dom в цикле.

   document.addEventListener('DOMContentLoaded', function () {
    var date = new Date();
    for (var i = 0; i < 70000; i++) {
        var tmpNode = document.createElement("div");
        tmpNode.innerHTML = "test" + i;
        document.body.appendChild(tmpNode);
    }
    console.log(new Date() - date);
}); 

Затраты времени на множественные измерения здесь составляют около 500 мс (операционная среда вся на стороне ПК, а ноутбук Xiaobawang). Увидев такой результат могут возникнуть сомнения, вот70000Модификация контента, есть70000Операция перекомпоновки заняла 500 мс (благодаря медленной операции dom), и перекомпоновка потребляет производительность.

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

  • offsetTop/Left/Width/Height
  • scrollTop/Left/Width/Height
  • clientTop/Left/Width/Height
  • getComputedStyle(), or currentStyle in IE

Второй код выглядит следующим образом:

        document.addEventListener('DOMContentLoaded', function () {
            var date = new Date();
            for (var i = 0; i < 70000; i++) {
                var tmpNode = document.createElement("div");
                tmpNode.innerHTML = "test" + i;
                document.body.offsetHeight; // 获取body的真实值
                document.body.appendChild(tmpNode);
            }
            console.log("speed time", new Date() - date);
        });

Большинству людей не следует запускать такой код.Если вы его запустите, поздравляю, ваш компьютер -1 с. Но без метрик оптимизация производительности невозможна.

«Если вы не можете что-то измерить, вы не можете это улучшить» — Лорд Кельвин.

Чтобы браузер не приостанавливал анимацию, количество циклов изменено на 7000 раз, и результат (среднее значение нескольких раз):

  • Время выборки ок.18000ms
  • Пример времени приблизительно без получения реального значения50ms

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

Уменьшить оплавление и перерисовку


Как уменьшить оплавление и перерисовку? вернуться к определению,reflow在页面布局或者定位发生变化时才会发生, из определения можно вывести как минимум две идеи оптимизации

  • Сокращение операций перекомпоновки
  • Переопределить свойства, запускающие перекомпоновку

Сокращение операций перекомпоновки

Суть его в уменьшении работы дерева рендеринга. Дерево рендеринга также является деревом рендеринга. Каждый его узел виден и содержит содержимое узла и соответствующий стиль правила. Это также самая большая разница между деревом рендеринга и количеством DOM. Чтобы уменьшить операцию перекомпоновки , основная цель состоит в том, чтобы объединить несколько перекомпоновок и, наконец, вернуть их в дерево рендеринга, например:

1, напрямую изменить имя класса

    // 不好的写法
    var left = 1;
    var top = 2;
    ele.style.left = left + "px";
    ele.style.top = top + "px";
    // 比较好的写法
    ele.className += " className1";

Или измените cssText напрямую:

    ele.style.cssText += ";
    left: " + left + "px;
    top: " + top + "px;";

2. Сделать часто перекомпоновываемые элементы «офлайн»

  • Используйте DocumentFragment для кэширования, запуска перекомпоновки и перерисовки;
  • С display:none, срабатывает только две перекомпоновки и перерисовки;
  • Используйте технологию cloneNode (true или false) и replaceChild, чтобы вызвать перекомпоновку и перерисовку;

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

    document.addEventListener('DOMContentLoaded', function () {
        var date = new Date(),
            fragment = document.createDocumentFragment();
        for (var i = 0; i < 7000; i++) {
            var tmpNode = document.createElement("div");
            tmpNode.innerHTML = "test" + i;
            fragment.appendChild(tmpNode);
        }
        document.body.appendChild(fragment);
        console.log("speed time", new Date() - date);
    });

Несколько результатов модификации хранятся в «складе» documentFragment. Этот процесс не повлияет на дерево рендеринга. После завершения цикла «инвентарь» этого «склада» будет добавлен в DOM для достижения цели. уменьшения перекомпоновки. То же самое верно и для использования cloneNode. Принцип использования display:none для уменьшения накладных расходов на перекомпоновку заключается в том, чтобы сделать узел недопустимым из дерева рендеринга, а затем «перейти в онлайн» после запуска нескольких операций перекомпоновки.

3. Сократите количество посещений, чтобы сбросить атрибуты очереди кеша.Если вы должны посетить, используйте кеш

// 不好的写法
for(let i = 0; i < 20; i++ ) { 
    el.style.left = el.offsetLeft + 5 + "px"; 
    el.style.top = el.offsetTop + 5 + "px"; 
}
// 比较好的写法
var left = el.offsetLeft, 
top = el.offsetTop, 
s = el.style; 
for (let i = 0; i < 20; i++ ) { 
    left += 5;
    top += 5; 
    s.left = left + "px"; 
    s.top = top + "px"; 
}

Переопределить свойства, запускающие перекомпоновку и перерисовку

Мы можем избежать перекомпоновки, заменив некоторые свойства, вызывающие перекомпоновку. Например, используйте translate вместо top и opacity вместо видимости.

Образец кода:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #react {
            position: relative;
            top: 0;
            width: 100px;
            height: 100px;
            background-color: red;
        }
    </style>
</head>

<body>
    <div id="react"></div>
    <script type="text/javascript">
        setTimeout(() => {
            document.getElementById("react").style.top = "100px"
        }, 2000);
    </script>
</body>
</html>

Код очень простой. На странице есть красный квадрат. Через 2 секунды его верхнее значение станет "100px". Чтобы легко отражать альтернативные свойства, можно избежать перекомпоновки. Здесь мы используем инструменты разработчика Chrome. Некоторые скриншоты следующие

Как показано на рисунке выше, на приведенном выше рисунке есть пять этапов, когда верхнее значение становится «100px».

  • Recalculate Style, браузер вычисляет измененный стиль
  • Макет, этот процесс мы называем процессом перекомпоновки
  • Обновить дерево слоев, обновить дерево слоев
  • Краска, процесс рисования слоя
  • Композитные слои, объединение нескольких слоев

Записываем время этих пяти процессов: 80 + Layout(73) + 72 + 20 + 69 =316us

Затем используйте translate вместо top:

-       position: relative;
-       top: 0;
+       transform: translateY(0);

-       document.getElementById("react").style.top = "100px"
+       document.getElementById("react").style.transform = "translateY(100px)"

Скриншот производительности:

Видно, что замена top на translate уменьшает исходный Layout, то есть процесс reflow.Time: 81+80+36+83=280us. В результате очень очевидно, что 315 мкс были уменьшены до 280 мкс. Некоторые люди говорят, что этот эффект не очевиден, но давайте представим такой бизнес-сценарий. Многие веб-сайты будут иметь плавающие окна, которые продолжают двигаться. Этот тип плавающего окна обычно реализуется с помощью таймера, а его верхняя часть изменяется каждые 100 мс. , если использовать translate, то можно уменьшить 10 переплавок за 1с.Если эркер имеет больше стилей и сложнее, то можно уменьшить 10 переплавок за 1 секунду.Сократите процесс верстки на сотни миллисекунд или даже секунд

Попробуем заменить видимость на непрозрачность.

-            document.getElementById("react").style.transform = "translateY(100px)"            
+            document.getElementById("react").style.visibility = "hidden"            

Скриншот производительности:

Изменение значения атрибута видимости вызовет только перерисовку, а не перекомпоновку, поэтому есть только четыре этапа, из которых третий этап, Paint, является воплощением перерисовки Время: 48 + 50 + Paint(14) + 71 =183us. Давайте заменим видимость на непрозрачность

+            opacity: 1;

-            document.getElementById("react").style.visibility = "hidden"    
+            document.getElementById("react").style.opacity = "0"

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

Да, вы все правильно прочитали, и я не ошибся, в этот раз не только не пропал процесс Paint, но даже появился Layout, я не удивлен! Не удивительно!
Давайте еще раз переопределим repaint, то есть перерисовать содержимое текущего слоя (что такое слой,нажмитеПосмотрите эту статью)

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

То есть браузер не может сделать альфа-канал всего слоя равным нулю, потому что в слое есть элемент с непрозрачностью 0, и весь слой не будет отображаться, поэтому есть два процесса Layout и Paint. . Решение тоже очень простое, то есть сразу сделать этот элемент отдельным слоем

Есть два способа изменить css для создания нового слоя:

  • будет изменяться: трансформироваться
  • преобразование: перевести Z (0)

Здесь мы используем следующие

+   transform: translateZ(0);

Скриншот производительности:

Теперь, как и в идеальной ситуации, замена видимости на непрозрачность позволяет избежать процесса перерисовки Paint. Посмотрим еще раз на время: 66 + 53 + 52 =171us

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

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

  • Уменьшить использование стола

  • Выбор скорости для реализации анимации

  • Новый слой для анимации

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

Использование слоев


В предыдущем примере мы создали новый слой для реализации непрозрачности вместо видимости, чтобы уменьшить возможность перерисовки, так как же еще можно использовать этот слой? Ответ да, мы можем использовать некоторые DOM элементы, которые часто перерисовываются и перекомпоновываются как слой, тогда эффект перерисовки и перекомпоновки этого DOM элемента будет только в этом слое, конечно, если создать слой для каждого элемента Слои, подобные этому, определенно будут умными и неправильными. Помните процесс на скриншоте производительности выше? Последний процесс композитных слоев заключается в объединении нескольких слоев. Слишком много слоев будет очень трудоемким. На самом деле, этот сам процесс также очень В принципе, новый слой будет создаваться при необходимости, чтобы уменьшить масштаб влияния перерисовки и перекомпоновки. В конце концов, если он не используется, разработчикам нужно балансировать в бизнес-сценариях. Слои можно создавать в браузере Chrome следующим образом:

  • Свойство CSS трехмерного или перспективного преобразования (перспективное преобразование)
  • тег видео с использованием ускоренного декодирования видео
  • Холст с 3D-контекстом (WebGL) или ускоренным 2D-контекстом
  • Гибридные плагины, такие как (например, Flash)
  • Анимируйте собственную непрозрачность с помощью CSS или используйте анимированный элемент, преобразованный с помощью webkit.
  • Элементы с ускоренными фильтрами CSS (ускорение GPU)
  • Элемент имеет дочерний узел, содержащий составной слой.
  • У элемента есть родственный элемент с меньшим z-индексом, который содержит составной слой.
  • will-change: transform;

Общая идея заключается в том, что мы используем DOM-элемент, который часто перерисовывается и перекомпоновывается как слой, тогда эффект от перерисовки и перекомпоновки этого DOM-элемента будет только в этом слое для повышения производительности. Например, давайте откроем Layers в инструментах разработчика Chrome, а затем откроем веб-сайт

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

Браузер подсветит перекрашиваемый в данный момент элемент зеленым, после проверки открываем видео:

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

Эпилог

В кратком обзоре этой статьи мы сначала говорили о том, что такое перекомпоновка и перерисовка, как их активировать, затем говорили о стратегиях, которые браузеры используют для их обработки, и, наконец, как избежать накладных расходов на производительность, вызванных перекомпоновкой и перерисовкой, и Также добавлен смысл и простота использования слоев. На самом деле в оптимизации reflow и repaint есть два момента:

  • Избегайте использования свойств css, которые вызывают перекомпоновку и перерисовку.
  • Ограничьте влияние перекомпоновки и перерисовки на отдельный слой

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

https://csstriggers.com

http://blog.csdn.net/luoshengyang/article/details/50661553