Мы очень рады видеть, что скорость некоторых распространенных операций DOM резко возросла. Изменения коснулись уровня WebKit, повысив производительность как Safari (JavaScriptCore), так и Chrome (V8).
Инженер Chrome Кентаро Хара провел семь оптимизаций кода в WebKit; ниже приведены результаты, которые показывают, насколько быстрее стал доступ к DOM с помощью JavaScript:
Сводка по повышению производительности DOM
- Производительность
div.innerHTML
иdiv.outerHTML
улучшена в 2,4 раза (V8, JavaScriptCore) - Производительность
div.innerText
иdiv.outerText
в Chromium/Mac увеличена в 4 раза (V8/Mac) - Доступ к свойствам CSS улучшен на 35 % (JavaScriptCore)
- Производительность
div.classList
,div.dataset
иdiv.attributes
улучшена до 10,9 раз (V8) - Производительность
div.firstElementChild
,lastElementChild
,previousElementSibling
иnextElementSibling
улучшена в 7,1 раз (V8) - Доступ к атрибутам DOM V8 улучшен на 4–5 % (V8).
Ниже Кентаро Хара подробно рассказывает о некоторых сделанных им патчах. Ссылки ведут на ошибки WebKit с тестовыми примерами, так что вы можете опробовать тесты самостоятельно. Изменения были внесены между WebKit r109829 и r111133: Chrome 17 их не включает; В Chrome 19 есть.
Повышение производительности div.innerHTML
и div.outerHTML
в 2,4 раза (V8, JavaScriptCore).
Предыдущее поведение в WebKit:
- Создайте строку для каждого тега.
- Добавьте созданную строку в
Vector<string>
, анализируя дерево DOM. - После анализа выделите строку, размер которой равен сумме всех строк в
Vector<string>
. - Объедините все строки в
Vector<string>
и верните ихinnerHTML
.
Новое поведение в WebKit: 1. Выделите одну строку, скажем, S. 1. Объедините строку для каждого тега с S, поэтапно анализируя дерево DOM. 1. Верните S как innerHTML
.
Короче говоря, вместо того, чтобы создавать множество строк и затем объединять их, патч создает одну строку, а затем просто постепенно добавляет строки.
Повышение производительности div.innerText
и div.outerText
в Chromium/Mac в 4 раза (V8/Mac).
Патч просто изменил первоначальный размер буфера для создания innerText
. Изменение исходного размера буфера с 2^16 на 2^15 улучшило производительность Chromium/Mac в 4 раза. Эта разница зависит от базовой системы malloc.
Повышение производительности доступа к свойствам CSS в JavaScriptCore на 35 %.
Строка свойства CSS (например, .fontWeight
, .backgroundColor
) преобразуется в целочисленный идентификатор в WebKit. Это преобразование является тяжелым. Патч кэширует результаты преобразования на карте (т. е. строку свойства => целочисленный идентификатор), так что преобразование не будет выполняться несколько раз.
Как работают тесты?
Они измеряют время доступа к собственности. В случае innerHTML
(тест производительности в bugs.webkit.org/show_bug.cgi?id=81214 ) тест просто измеряет время выполнения следующего кода:
for (var i = 0; i < 1000000; i++)
document.body.innerHTML;
Тест производительности использует большое тело, скопированное из спецификации HTML.
Аналогично, тест доступа к свойствам CSS измеряет время выполнения следующего кода:
var spanStyle = span.style;
for (var i = 0; i < 1000000; i++) {
spanStyle.invalidFontWeight;
spanStyle.invalidColor;
spanStyle.invalidBackgroundColor;
spanStyle.invalidDisplay;
}
Хорошей новостью является то, что Кентаро Хара считает, что для других важных атрибутов и методов DOM можно будет повысить производительность.
Давай!
Слава Харакену и остальной команде.