Разница в производительности между созданными встроенными стилями JavaScript и созданными в стиле JavaScript стилями
Я хочу динамически стилизовать все элементы данного селектора в моей DOM. Я вижу более или менее два пути. В приведенном ниже примере я использую элемент p
и его атрибут text-align
, но меня больше интересуют плюсы и минусы двух возможных способов сделать это, чем я в специально абзацах, выравнивающих текст.
1. Встроенный (для элемента) стили
var nodes = document.getElementsByTagName('p');
Array.prototype.forEach.call (nodes, function (node) {
node.style.textAlign = "center";
});
2. Стили
var sheet = (function() {
// Create the <style> tag
var style = document.createElement("style");
// WebKit hack :(
style.appendChild(document.createTextNode(""));
// Add the <style> element to the page
document.head.appendChild(style);
return style.sheet;
})();
sheet.insertRule("p { text-align: center; }");
Как правило, я бы пошел по пути встроенных стилей, поскольку он кажется более простым и гарантирует, что изменение стиля переопределит существующие таблицы стилей. Но мне приходит в голову, что для одного: иногда не переопределение таблиц стилей может быть предпочтительным, а для двоих: может быть больше производительности изменить один элемент style
, чем неизвестное количество элементов p
. Но это только мое предположение.
Производительность была бы такой, если бы когда-либо была ситуация, когда применение встроенных стилей для каждого отдельного элемента было бы лучше, чем создание таблицы стилей? Предполагая, что ответ может зависеть от того, сколько элементов я стилю, в какой-то момент создание таблицы стилей становится более эффективным?
EDIT: Чтобы выяснить, почему я задаю этот вопрос, я немного объясню, почему я спрашиваю: недавно я включил несколько хакеров JS, которые я часто копировал и адаптировал между проектами в набор многоразовых модулей CommonJS. Они делают такие вещи, как установка всех элементов заданного селектора той же высоты или ширины, что и самый высокий или самый широкий из наборов в ситуациях, когда измерение самого высокого или самого широкого может быть изменено при изменении размера окна или других триггеров.
Вот сообщение в блоге об этом: http://davejtoews.com/blog/post/javascript-layout-hacks
Вот репозитории GitHub для модулей:
В этот момент все эти модули используют встроенные стили, но я думаю о переключении их на таблицы стилей. Я не мог найти хороший ответ о плюсах и минусах любого подхода, поэтому я разместил здесь этот вопрос.
Ответы
Ответ 1
У меня нет хорошего общего ответа на ваш вопрос (и я не уверен, что он есть), но я провел несколько экспериментов с примером, который вы опубликовали в Chrome 57.0.2987.98 beta, используя инструменты dev график.
Вот разбивка работы, выполненной в одном кадре, которая обновляет 10000 <p>
элементов со встроенными стилями (слева) и динамической таблицей стилей (справа):
![inline]()
![stylesheet]()
Для сравнения приведены результаты для одного и того же теста с 100 <p>
элементами:
![inline]()
![stylesheet]()
Таким образом, для небольшого числа элементов разница незначительна. Для большого количества элементов при использовании встроенных стилей браузер тратит больше времени на скриптинг (чего следует ожидать, поскольку существует тяжелый цикл) и пересчет стилей ( Я думаю, это может быть объяснено браузером, который должен анализировать одно правило стиля для каждого элемента, а не одно общее правило стиля).
Все остальные шаги занимают примерно одинаковое количество времени. В частности, время рисования не увеличивается при использовании встроенных стилей.
Для справки я использовал следующую тестовую страницу.
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<button id="add-stylesheet">Stylesheet</button>
<button id="add-inline-styles">Inline</button>
<script type="text/javascript">
let stylesheet = document.getElementById('add-stylesheet');
let inline = document.getElementById('add-inline-styles');
stylesheet.addEventListener('click', addStylesheet);
inline.addEventListener('click', addInlineStyles);
function addStylesheet() {
let style = document.createElement("style");
style.appendChild(document.createTextNode(""));
document.head.appendChild(style);
style.sheet.insertRule('p { text-align: center }', 0);
}
function addInlineStyles() {
let nodes = document.getElementsByTagName('p');
for (let node of nodes) {
node.style.textAlign = 'center';
}
}
// initialize <p> elements
init(10000);
function init(numElements) {
for (let i = 0; i < numElements; ++i) {
let p = document.createElement('p');
p.innerText = 'testing'
document.body.appendChild(p);
}
}
</script>
</html>
Ответ 2
Плюсы и минусы встроенных стилей
Прошло много споров по этому вопросу за последние пару лет, так как React и JSX получили огромную популярность.
Я попробовал несколько решений, поэтому я перечислил их здесь. Сначала общая дискуссия.
CSS - это, в основном, единственный язык, который защищает использование глобального пространства имен, и это причина номер 1, от которой люди отходят от прямого CSS и тяжелых всеобъемлющих фреймворков. С flexbox отзывчивые макеты могут выполняться несколькими строками кодов, а не всей сеткой, например, вы получите что-то вроде бутстрапа.
CSS решила проблему предоставления стилей документам многоразового использования, но по мере того как приложения стали более масштабными и сложными, и было включено больше сторонних библиотек со своим собственным CSS, вероятность глобальных конфликтов пространства имен стала практически неизбежной. Настолько, что было создано несколько разных шаблонов, за которые выступали, например, BEM и SMACSS.
Появилась реакция, которая сделала управление и создание многоразовых встроенных стилей относительно простым. Вы можете использовать все javascript, что означает, что вы можете переопределять стили, используя такие вещи, как _.extend
или Object.assign
. Это упростило обмен модулями и пакетами, включающими компоненты и их стили, и имело преимущество не требовать какого-либо стиля загрузчика, например, того, что требуется при использовании webpack
. Однако это были не все розы. Такие вещи, как :hover
, другие псевдоселекторы и медиа-запросы, не поддерживаются в простых встроенных стилях.
Чтобы обойти эти ограничения, разработчики внедрили события, чтобы инициировать изменения стиля, например onmouseover
для зависания, и подключаться к событиям изменения размера окна для медиа-запросов. Вскоре после этого была создана библиотека для стандартизации этих событий js и определения CSS, как API, и получил популярность под названием Radium
. В дикой природе Радий тоже не был справедлив (поверьте, я попробовал). В больших приложениях ни один из медиа-запросов не может выполняться до тех пор, пока все JS не будут загружены, что я не рекомендую!
Это привело к созданию нескольких новых инструментов, которые используют другой подход. Эти инструменты нового поколения используют стили, определенные в JS, но генерируют CSS. Это дает вам полную силу встроенных стилей и полную мощность CSS. Лучшее обоих миров. Какая библиотека лучше всего зависит от вашего варианта использования, но они состоят из Fela.js, Aphrodite и JSS.
Мое любимое решение - Fela.js. Проверьте это на fela.js.org. Fela, вероятно, лучший результат, который вы собираетесь получить, и это не относится к какой-либо конкретной структуре. Это, как говорится, хорошо работает с React and React Native. В нем есть несколько опрятных функций, таких как доступ к реквизитам из ваших стилей. Вы настроили renderer
в начале страницы. Fela лучше всего работает с SSR, но также работает на стороне клиента в зависимости от ваших потребностей. При использовании с SSR вы можете получить яркие быстрые загрузки страниц, потому что Fela оптимизирует стили, которые вы написали, в классы атомного класса css, и они отправляются обратно клиенту по первоначальному запросу.
Эти инструменты поразительны, если вас беспокоит возможность получения самой быстрой страницы. Вы можете легко выполнить сложные шаблоны, такие как оптимизация критического пути css, где необходимые стили возвращаются как часть исходного HTTP-запроса, а не ссылка на внешний лист, который также необходимо загрузить.
Наконец, я должен упомянуть модули CSS. Они создают внешнюю таблицу стилей, но позволяют вам по-прежнему иметь CSS с именами для каждого модуля. Это позволяет писать настоящие CSS или SASS и т.д., Но поставляется с дополнительными накладными расходами. Например, в веб-пакете вам нужно будет использовать комбинацию поддельных загрузчиков стиля и инструментов для извлечения текста для создания файла .css.
Ответ 3
Все зависит от контекста того, что вы пытаетесь выполнить. На моем нынешнем работодателе я создал небольшую библиотеку под названием stylo, которая отвечает за обновление динамической таблицы стилей.
Когда количество элементов, которые вы пытаетесь обновить, находится в тысячах, тогда обновление через встроенные стили будет чрезмерно дорогостоящим. Демонстрация в ссылке выше обновляет 6400 элементов за долю секунды.
Однако, если вы обновляете только несколько элементов, обновление таблицы стилей может вызвать повторную визуализацию всей страницы, которая не будет иметь места, если обновлен встроенный стиль.