HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO —...
Transcript of HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO —...
![Page 1: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/1.jpg)
CSSO — история ускорения
Роман Дворнов Avito
HolyJS
Санкт-Петербург, 2016
![Page 2: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/2.jpg)
Работаю в Avito
Делаю SPA
Автор basis.js
Мейнтенер CSSO
За любую движуху, кроме голодовки ;)
![Page 3: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/3.jpg)
Врем
я сж
атия
CSS
(600
Kb)
500 ms
1 000 ms
1 500 ms
2 000 ms
2 500 ms
3 000 ms
3 500 ms
4 000 ms
4 500 ms
5 000 ms
5 500 ms
6 000 ms
Версия CSSO
1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0
1 050 msclean-css
Изменение скорости CSSO
csso500 ms
cssnano23 250 ms
![Page 4: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/4.jpg)
Почему это важно?
![Page 5: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/5.jpg)
5
clean-css 3.4.16 cssnano 3.6.2 csso 2.1.1
ноябрь 2015602 245 байт
430 2402 039 ms
439 21041 355 ms
435 629714 ms
апрель 2016822 021 байт
587 9062 546 ms
604 16776 665 ms
595 834793 ms
июнь 2016883 498 байт
632 0072 588 ms
648 57994 867 ms
639 495803 ms
Время минификации CSSОсновной CSS файл ActiAgent.ru
![Page 6: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/6.jpg)
Тренд изменения времени от размера CSSТр
енд из
мене
ний ра
змер
а и вр
емен
и
100 %
120 %
140 %
160 %
180 %
200 %
220 %
240 %
Размер CSS
602 245 822 021 883 498
размер CSS clean-css cssnano csso
229%
146%
127%112%
![Page 7: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/7.jpg)
7
Новые продвинутые оптимизации(usage data, rename, etc)
245 823
Время
Размер (байт) 639 495
803 ms 2 513 ms
Лучше сжатие, но требует 2-3х больше времени
![Page 8: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/8.jpg)
8
clean-css 3.4.16 cssnano 3.6.2 csso 2.1.1
15,5 sec 9 min 29 sec 4,8 sec
Таких файлов в проекте несколько (6 больших)время минификации всех файлов
![Page 9: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/9.jpg)
8
clean-css 3.4.16 cssnano 3.6.2 csso 2.1.1
15,5 sec 9 min 29 sec 4,8 sec
Таких файлов в проекте несколько (6 больших)время минификации всех файлов
clean-css 3.4.16 cssnano 3.6.2 csso 2.1.1
не поддерживается
(≈46,5 sec)не поддерживается
(≈28 min 27 sec) ~15 sec
+ продвинутые оптимизации
![Page 10: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/10.jpg)
9
CSS
сжатый CSS
Процесс минификации
![Page 11: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/11.jpg)
9
CSS
сжатый CSS
Парсер
Процесс минификации
![Page 12: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/12.jpg)
9
CSS
сжатый CSS
ASTПарсер
Процесс минификации
![Page 13: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/13.jpg)
9
CSS
сжатый CSS
ASTПарсер
Компрессор
Процесс минификации
![Page 14: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/14.jpg)
9
CSS
сжатый CSS
AST
AST
Парсер
Компрессор
Процесс минификации
![Page 15: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/15.jpg)
9
CSS
сжатый CSS
AST
AST
Парсер
Компрессор
Транслятор
Процесс минификации
![Page 16: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/16.jpg)
9
CSS
сжатый CSS
AST
AST
Парсер
Компрессор
Транслятор
Процесс минификации
Минификатор
![Page 17: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/17.jpg)
Парсер
![Page 18: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/18.jpg)
Основные шаги
• Токенизация
• Построение дерева (лексер)
11
![Page 19: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/19.jpg)
Токенизация
![Page 20: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/20.jpg)
13
• whitespaces – [ \n\r\t\f]+ • keyword – [a-zA-aZ…]+ • number – [0-9]+ • string – "string" или 'string' • comment – /* comment */ • punctuation – [;,.#\{\}\[\]\(\)…]
Разбиение текста на токены
![Page 21: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/21.jpg)
14
.foo { width: 10px;}
[ '.', 'foo', ' ', '{', '\n ', 'width', ':', ' ', '10', 'px', ';', '\n', '}']
![Page 22: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/22.jpg)
Низкоуровневые штуки
![Page 23: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/23.jpg)
16
for (var i = 0; i < str.length; i++) { var ch = str.charAt(i); var chNext = str.charAt(i + 1); if (ch === '/' && chNext === '*') { result.push(readComment()); } else if (ch >= '0' && ch <= '9') { result.push(readNumber()); } ...}
Ключевой цикл токенайзера
![Page 24: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/24.jpg)
17
for (var i = 0; i < str.length; i++) { var ch = str.charAt(i); var chNext = str.charAt(i + 1); if (ch === '/' && chNext === '*') { result.push(readComment()); } else if (ch >= '0' && ch <= '9') { result.push(readNumber()); } ...}
Ключевой цикл токенайзера
![Page 25: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/25.jpg)
18
for (var i = 0; i < str.length; i++) { var ch = str.charAt(i); var chNext = str.charAt(i + 1); if (ch === '/' && chNext === '*') { result.push(readComment()); } else if (ch >= '0' && ch <= '9') { result.push(readNumber()); } ...}
Ключевой цикл токенайзера
![Page 26: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/26.jpg)
19
for (var i = 0; i < str.length; i++) { var ch = str.charAt(i); var chNext = str.charAt(i + 1); if (ch === '/' && chNext === '*') { result.push(readComment()); } else if (ch >= '0' && ch <= '9') { result.push(readNumber()); } ...}
Ключевой цикл токенайзера
![Page 27: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/27.jpg)
20
for (var i = 0; i < str.length; i++) { var ch = str.charAt(i); var chNext = str.charAt(i + 1); if (ch === '/' && chNext === '*') { result.push(readComment()); } else if (ch >= '0' && ch <= '9') { result.push(readNumber()); } ...}
Ключевой цикл токенайзера
![Page 28: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/28.jpg)
Обычный код – простор для потери быстродействия
21
![Page 29: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/29.jpg)
Строки vs. числа
![Page 30: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/30.jpg)
23
for (var i = 0; i < str.length; i++) { var ch = str.charAt(i); var chNext = str.charAt(i + 1); if (ch === '/' && chNext === '*') { result.push(readComment()); } else if (ch >= '0' && ch <= '9') { result.push(readNumber()); } ...}
Сравнение символов
![Page 31: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/31.jpg)
24
• Строка – последовательность чисел
• Извлечение символа = получение новой строки
• Сравнение символов ≈ сравнение строк
Нужно помнить
![Page 32: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/32.jpg)
25
!!!
![Page 33: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/33.jpg)
26
// выносим коды символов в константыvar STAR = 42;var SLASH = 47;var ZERO = 48;var NINE = 57;...
Делаем быстрее
![Page 34: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/34.jpg)
27
for (var i = 0; i < str.length; i++) { var code = str.charCodeAt(i); var codeNext = str.charCodeAt(i + 1); if (code === SLASH && codeNext === STAR) { result.push(readComment()); } else if (code >= ZERO && code <= NINE) { result.push(readNumber()); } ...}
charCodeAt() + числовые константы
![Page 35: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/35.jpg)
28
✔Нет больше
StringCharFromCode
✔Всегда сравнение
чисел
![Page 36: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/36.jpg)
28
✔Нет больше
StringCharFromCode
✔Всегда сравнение
чисел
???Загрузка значения перед сравнением
![Page 37: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/37.jpg)
Используй const, Люк!
29
var STAR = 42;var SLASH = 47;var ZERO = 48;var NINE = 57;...
const STAR = 42;const SLASH = 47;const ZERO = 48;const NINE = 57;...
![Page 38: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/38.jpg)
30
WTF?
![Page 39: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/39.jpg)
– Вячеслав Егоров
“... [const] это все-таки неизменяемая привязка переменной к значению ...
С другой стороны виртуальная машина может и должна бы использовать это самое свойство неизменяемости ...
V8 не использует, к сожалению.”
31
habrahabr.ru/company/jugru/blog/301040/#comment_9622474
![Page 40: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/40.jpg)
32
for (var i = 0; i < str.length; i++) { var code = str.charCodeAt(i); var codeNext = str.charCodeAt(i + 1); if (code === 47 && codeNext === 42) { result.push(readComment()); } else if (code >= 48 && code <= 57) { result.push(readNumber()); } ...}
Но мы люди упоротые упорные
![Page 41: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/41.jpg)
32
for (var i = 0; i < str.length; i++) { var code = str.charCodeAt(i); var codeNext = str.charCodeAt(i + 1); if (code === 47 && codeNext === 42) { result.push(readComment()); } else if (code >= 48 && code <= 57) { result.push(readNumber()); } ...}
Но мы люди упоротые упорные
Положительный эффект не замечен…
![Page 42: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/42.jpg)
33
356ms – chatAt() 307ms – charCodeAt()
Результаты
на ~14% быстрее
![Page 43: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/43.jpg)
Осторожней со строками
![Page 44: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/44.jpg)
35
for (var i = 0; i < str.length; i++) { var code = str.charCodeAt(i); var codeNext = str.charCodeAt(i + 1); if (code === SLASH && codeNext === STAR) { result.push(readComment()); } else if (code >= ZERO && code <= NINE) { result.push(readNumber()); } ...}
Избегаем лишних чтений из строки
![Page 45: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/45.jpg)
36
for (var i = 0; i < str.length; i++) { var code = str.charCodeAt(i); if (code === SLASH) { var codeNext = str.charCodeAt(i + 1); if (codeNext === STAR) { result.push(readComment()); continue; } } ...}
Избегаем лишних чтений из строки
307ms → 292 ms (-5%)
![Page 46: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/46.jpg)
37
for (var i = 0; i < str.length; i++) { var code = str.charCodeAt(i); if (code === SLASH) { var codeNext = str.charCodeAt(i + 1); if (codeNext === STAR) { result.push(readComment()); continue; } } ...}
Опасная операция!
![Page 47: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/47.jpg)
38
Попытка чтения за пределами строки или массива
приводит к деоптимизации
![Page 48: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/48.jpg)
39
var codeNext = 0;if (i + 1 < str.length) { codeNext = str.charCodeAt(i + 1);}
Избегаем выхода за пределы строки
292ms → 69 ms (в 4 раза быстрее!)
![Page 49: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/49.jpg)
Меньше сравнений
![Page 50: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/50.jpg)
41
if (code >= ZERO && code <= NINE) { // число} else if (code === SINGLE_QUOTE || code === DOUBLE_QUOTE) { // строка} else if (code === SPACE || code === N || code === R || code === F) { // whitespace} …
Много сравнений
![Page 51: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/51.jpg)
42
var PUNCTUATION = { 9: 'Tab', // '\t' 10: 'Newline', // '\n' ... 126: 'Tilde' // '~'};...} else if (code in PUNCTUATION) { // символ пунктуации} ...
Проверка в словаре – очень дорого
![Page 52: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/52.jpg)
43
var CATEGORY_LENGTH = Math.max.apply(null, Object.keys(PUNCTUATION)) + 1;var CATEGORY = new Uint32Array(CATEGORY_LENGTH);
Object.keys(PUNCTUATION).forEach(function(key) { CATEGORY[key] = PUNCTUATOR;});
for (var i = ZERO; i <= NINE; i++) { CATEGORY[i] = DIGIT;}
CATEGORY[SINGLE_QUOTE] = STRING;CATEGORY[DOUBLE_QUOTE] = STRING;CATEGORY[SPACE] = WHITESPACE;...
Создаем карту категорий
![Page 53: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/53.jpg)
44
switch (code < CATEGORY_LENGTH ? CATEGORY[code] : 0) { case DIGIT: // число case STRING: // строка case WHITESPACE: // whitespace case PUNCTUATOR: // символ пунктуации ...}
Уменьшаем число сравнений
69ms → 14 ms (еще в 5 раз быстрее!)
![Page 54: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/54.jpg)
Предварительные итоги
![Page 55: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/55.jpg)
Результат: 356ms → 14 ms Цифры получены на упрощенном примере, на практике всё сложнее
Примеры тестов: gist.github.com/lahmatiy/e124293c2f2b98e847d0f2bb54c2738e
46
![Page 56: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/56.jpg)
47
• charAt() → charCodeAt()
• Избегайте лишних операций со строками
• Контролируйте выход за пределы
• Уменьшайте количество сравнений
Подводим итоги
![Page 57: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/57.jpg)
Токен – не только строка
![Page 58: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/58.jpg)
Нужна дополнительная информация о токене: тип и локация
49
![Page 59: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/59.jpg)
50
.foo { width: 10px;}
[ { type: 'FullStop', value: '.', offset: 0, line: 1, column: 1 }, …]
![Page 60: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/60.jpg)
Как хранить?
51
Object ArrayПонятнее Компактнее
{ type: 'FullStop', value: '.', offset: 1, line: 2, column: 3}
['FullStop', '.', 1, 2, 3]
![Page 61: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/61.jpg)
Размер токена
52
Object Array64 байт 88 байт
![Page 62: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/62.jpg)
Размер токена
52
Object Array64 байт 88 байт
Наш CSS – 885Kb 256 163 токена
16,4 Мб 22,5 Мбразница 6,1 Мб
![Page 63: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/63.jpg)
Что быстрее?
53
Object Array
Время создания (литералов) сопоставимо, меняется в зависимости от задачи
Обработка объектов (чтение) гораздо быстрее
Нет простого ответа
gist.github.com/lahmatiy/90fa91d5ea89465d08c7db1e591e91c2
![Page 64: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/64.jpg)
Меняем подход
![Page 65: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/65.jpg)
Последовательные токенайзер и лексер – проще,
но ведет к лишним затратам памяти и медленней
55
![Page 66: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/66.jpg)
Scanner (ленивый токенайзер)
56
![Page 67: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/67.jpg)
57
scanner.token // текущий токен или nullscanner.next() // переход к следующему токенуscanner.lookup(N) // заглядывание вперед, возвращает // токен на N-ой позиции от текущей
Основное API
![Page 68: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/68.jpg)
58
• lookup(N) заполняет буфер токенов до позиции N, если еще не заполнен, возвращает N-1 токен из буфера
• next()делает shift из lookup буфера, если он не пустой, либо читает новый токен
![Page 69: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/69.jpg)
Создается столько же токенов, но нужно меньше памяти в один
момент времени
59
![Page 70: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/70.jpg)
60
• Переиспользование объектов токенов
• Пул токенов фиксированного размера
Неудачные эксперименты
Выигрыш практически не ощущается, но код гораздо сложнее и в разных случаях нужен пул
разного размера, иногда очень большой
![Page 71: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/71.jpg)
Сборка дерева
![Page 72: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/72.jpg)
62
• Избавление от look ahead
• Array → Object
• Array → List
• CST → AST
• …
Как ускорялся
![Page 73: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/73.jpg)
Look ahead
![Page 74: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/74.jpg)
64
function getSelector() { var node = ['Selector']; while (i < tokens.length) { if (checkId()) { node.push(getId()); } else if (checkClass()) { node.push(getClass()); } else ... } return node;}
Было
![Page 75: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/75.jpg)
65
function getSelector() { var node = ['Selector']; while (i < tokens.length) { if (checkId()) { node.push(getId()); } else if (checkClass()) { node.push(getClass()); } else ... } return node;}
Было
Checker-функции – проверяют, подходящая ли последовательность токенов чтобы собрать AST узел
![Page 76: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/76.jpg)
66
function getSelector() { var node = ['Selector']; while (i < tokens.length) { if (checkId()) { node.push(getId()); } else if (checkClass()) { node.push(getClass()); } else ... } return node;}
БылоBuild-функции – собирают AST узел, у них есть гарантия, что впереди подходящая последовательность токенов
![Page 77: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/77.jpg)
67
• Многократный проход по списку токенов
• Нужны все токены сразу
• Большое дублирование кода (проверок)
• Сложно определить местоположение, в случае синтаксической ошибки в CSS
Проблемы
![Page 78: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/78.jpg)
68
StyleSheet Ruleset Selector SimpleSelector Id | Class | Attribute … … Block … …
Насколько все плохоcheckStyleSheet() проверяла всю последовательность токенов, прежде чем начиналась сборка AST
![Page 79: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/79.jpg)
– Cascading Style Sheets Level 2 Specification
“The lexical scanner for the CSS core syntax in section 4.1.1 can be implemented as a scanner without back-up.”
69
www.w3.org/TR/CSS22/grammar.html#q4
![Page 80: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/80.jpg)
70
while (scanner.token !== null) { switch (scanner.token.type) { case TokenType.Hash: // # node.push(getId()); break; case TokenType.FullStop: // . node.push(getClass()); break; … }
СталоБыстрая проверка типа токена. В большинстве случае этого достаточно, чтобы выбрать подходящую функцию сборки
![Page 81: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/81.jpg)
71
function getPseudo() { var next = scanner.lookup(1);
if (next.type === TokenType.Colon) { return getPseudoElement(); }
return getPseudoClass();}
СталоЗаглядывать вперед нужно редко, в этих случаях используется scanner.lookup(N)
![Page 82: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/82.jpg)
72
if (scanner.token.type !== TokenType.Something) { throwError('Something wrong here');}
Стало
Если встречается что-то "не то" – тут же выбрасывается сообщение об ошибке
![Page 83: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/83.jpg)
73
• Значительно быстрее
• Используется ленивый токенайзер
• Код проще, мало дублирования
• Точное местоположение для ошибок в CSS
Сплошные плюсы
![Page 84: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/84.jpg)
Array → Object
![Page 85: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/85.jpg)
75
[ "stylesheet", [ "atrules", [ "atkeyword", [ "ident", "import" ] ], [ "s", " " ], [ "string", "'path/to/file.css'" ] ]]
Было – массив массивов
![Page 86: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/86.jpg)
76
{ "type": "StyleSheet", "rules": [{ "type": "Atrule", "name": "import", "expression": { "type": "AtruleExpression", "sequence": [ ... ] }, "block": null }]}
Стало
![Page 87: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/87.jpg)
77
• Требуется меньше памяти
• Быстрее работа с узлами
• Проще писать/читать код (node[1] vs. node.value)
Результат
![Page 88: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/88.jpg)
78
Помни – меньше мутаций!function createNode() { var node = { type: 'Type' };
if (expression1) { node.foo = 123; } if (expression2) { node.bar = true; }
return node;}
При добавлении нового свойства создается новый hidden class (здесь до 4). Узел одного типа, но объекты разных классов – принимающие функции станут полиморфными.
![Page 89: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/89.jpg)
79
Добавляется новое свойство → меняется hidden class
![Page 90: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/90.jpg)
80
Смена hidden class
![Page 91: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/91.jpg)
81
Фиксимfunction createNode() { var node = { type: 'Type', foo: null, bar: false };
if (expression1) { node.foo = 123; } if (expression2) { node.bar = true; }
return node;}
При создании объекта стоит указывать все возможные свойства – будет один hidden class
![Page 92: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/92.jpg)
82
Все стало проще
И функции работающие с объектами только этого типа будут мономорфными
![Page 93: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/93.jpg)
CST → AST
![Page 94: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/94.jpg)
84
• AST (Abstract Syntax Tree)логическая структура
• CST (Concrete Syntax Tree)логическая структура + информация о форматировании
AST vs. CST
![Page 95: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/95.jpg)
85
• AST – не нужно форматирование linters, minifiers, beautifiers, …
• CST – форматирование важноlinters, autoprefixer, postcss и друзья
AST vs. CST
![Page 96: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/96.jpg)
Раньше парсер возвращал CST, то есть сохранял все
пробелы, комментарии и разделители
86
![Page 97: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/97.jpg)
87
.foo > .bar,
.baz { border: 1px solid red; // I'm useless comment}
Отмеченное желтым – не нужно, но сохранялось в дереве, а компрессор
это все удалял
![Page 98: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/98.jpg)
Так же теперь парсер не собирает заведомо неверные конструкции,
что упрощает и ускоряет дальнейшую работу с деревом
(т.к. не требуются лишние проверки)
88
![Page 99: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/99.jpg)
89
{ "type": "Dimension", "value": { "type": "Number", "value": "123" }, "unit": { "type": "Identifier", "name": "px" }}
Упрощен формат некоторых узлов
{ "type": "Dimension", "value": "123", "unit": "px"}
![Page 100: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/100.jpg)
90
• Меньше узлов в дереве
• Не нужен обход, чтобы удалить ненужное
• Многое проще не добавлять в дерево, чем потом искать и удалять
Результат
![Page 101: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/101.jpg)
91
• Наш CSS – 885Kb
• было узлов – 281 750
• стало узлов – 139 858
• Экономия памяти ~7Mb
• В два раза быстрее обход
В цифрах
![Page 102: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/102.jpg)
Подводим итоги
![Page 103: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/103.jpg)
93
• В ~5 раз быстрее
• В ~3 раза меньше потребление памяти
• Проще формат
• Дешевле обход и обработка AST
Улучшения парсера
![Page 104: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/104.jpg)
Компрессор
![Page 105: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/105.jpg)
95
• Однопроходная реструктуризация
• Уменьшение числа обходов
• Уменьшение глубины обхода
• Минимум вычислений, мутаций узлов, копирования
• Учет специфики CSS
• …
Как ускорялся
![Page 106: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/106.jpg)
Однопроходная реструктуризация
![Page 107: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/107.jpg)
97
var prevAst = ast;var prev = translate(ast);while (true) { var resAst = restruct(copy(prevAst)); var res = translate(resAst);
if (res.length > prev.length) { resAst = prevAst; break; }
prevAst = resAst; prev = res;}
Трансформируем пока есть положительный эффект
![Page 108: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/108.jpg)
98
var prevAst = ast;var prev = translate(ast);while (true) { var resAst = restruct(copy(prevAst)); var res = translate(resAst);
if (res.length > prev.length) { resAst = prevAst; break; }
prevAst = resAst; prev = res;}
На каждой итерации • копирование дерева
![Page 109: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/109.jpg)
99
var prevAst = ast;var prev = translate(ast);while (true) { var resAst = restruct(copy(prevAst)); var res = translate(resAst);
if (res.length > prev.length) { resAst = prevAst; break; }
prevAst = resAst; prev = res;}
На каждой итерации • копирование дерева • трансляция в строку
![Page 110: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/110.jpg)
100
var prevAst = ast;var prev = translate(ast);while (true) { var resAst = restruct(copy(prevAst)); var res = translate(resAst);
if (res.length > prev.length) { resAst = prevAst; break; }
prevAst = resAst; prev = res;}
На каждой итерации • копирование дерева • трансляция в строку •бай-бай GC
![Page 111: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/111.jpg)
101
var prevAst = ast;var prev = translate(ast);while (true) { var resAst = restruct(copy(prevAst)); var res = translate(resAst);
if (res.length > prev.length) { resAst = prevAst; break; }
prevAst = resAst; prev = res;}
На каждой итерации • копирование дерева • трансляция в строку •бай-бай GC
😱
![Page 112: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/112.jpg)
Стало
102
restruct(ast);
• Не ошибка – один проход
• Нет копирования AST, трансляции всего дерева в строку
• Пришлось поменять алгоритмы
• Меньше нагрузка на GC, быстрее в 3-4 раза
![Page 113: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/113.jpg)
Глубина обхода
![Page 114: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/114.jpg)
104
Наш CSS – 885Kb
139 858 узлов
Холостой обход дерева
31 ms
![Page 115: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/115.jpg)
Многим трансформациям необходимо обходить лишь
Ruleset и AtRule
105
![Page 116: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/116.jpg)
106
• walkAll() – обход всех узлов
• walkRules() – обход только правил и at-rules
• walkRulesRight() – обход только правил и at-rules в обратном порядке
Walker под задачу
![Page 117: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/117.jpg)
107
Наш CSS – 139 858 узлов
walkAll()
31 ms
Холостой обход дерева
walkRules(), walkRulesRight()
2 msобходится 6 154 узла (4%)
![Page 118: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/118.jpg)
Меньше обходов
![Page 119: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/119.jpg)
109
walkAll(ast, function(node) { if (node.type === 'Number') { … }});walkAll(ast, function(node) { if (node.type === 'String') { … }});…
БылоДля каждого типа узла отдельный обход Как мы помним, для нашего дерева операция стоит 31 ms
![Page 120: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/120.jpg)
110
walkAll(ast, function(node) { if (node.type === 'Number') { … }});walkAll(ast, function(node) { if (node.type === 'String') { … }});…
БылоФункции получают все узлы дерева, а они разных hidden class. Так функции будут полиморфными, хотя работают (обычно) только с одним типом узлов
![Page 121: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/121.jpg)
111
var handlers = { Number: packNumber, String: packString, …};
walkAll(ast, function(node, item, list) { if (handlers.hasOwnProperty(node.type)) { handlers[node.type].call(this, node, item, list); }});
СталоОдин проход
![Page 122: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/122.jpg)
112
var handlers = { Number: packNumber, String: packString, …};
walkAll(ast, function(node, item, list) { if (handlers.hasOwnProperty(node.type)) { handlers[node.type].call(this, node, item, list); }});
СталоЕдинственная полиморфная функция, но простая
![Page 123: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/123.jpg)
113
var handlers = { Number: packNumber, String: packString, …};
walkAll(ast, function(node, item, list) { if (handlers.hasOwnProperty(node.type)) { handlers[node.type].call(this, node, item, list); }});
СталоФункции оказываются мономорфными (им приходят объекты одного hidden class)
![Page 124: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/124.jpg)
114
var handlers = { Number: packNumber, String: packString, …};
walkAll(ast, function(node, item, list) { if (handlers.hasOwnProperty(node.type)) { handlers[node.type].call(this, node, item, list); }});
СталоПо результатам экспериментов, наиболее быстрый вариант решения
![Page 125: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/125.jpg)
Общий итог
![Page 126: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/126.jpg)
116
• В 10+ раз быстрее
• В 7+ раз меньше потребление памяти
• В настоящий момент быстрее и эффективнее по ресурсам других структурных минификаторов (cssnano, clean-css)
Текущие результаты
goalsmashers.github.io/css-minification-benchmark/
![Page 127: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/127.jpg)
Работы не закончены, можно сделать еще лучше ;)
117
![Page 128: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/128.jpg)
CSSO — сжимаем CSS
118
www.slideshare.net/basisjs/csso-css-2
Немного о принципах минификации, новых продвинутых оптимизациях и открытых вопросах
![Page 129: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/129.jpg)
Бонус трек
![Page 130: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/130.jpg)
Обкладывайте операции замерами
120
> echo '.test { color: green; }' | csso --debug## parsing done in 11 ms
Compress block #1[0.000s] init[0.001s] clean[0.001s] compress[0.004s] prepare[0.001s] initialMergeRuleset[0.000s] mergeAtrule[0.000s] disjoinRuleset[0.001s] restructShorthand[0.003s] restructBlock...
![Page 131: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/131.jpg)
Hi-res timing
121
var startTime = process.hrtime();// your codevar elapsed = process.hrtime(startTime);console.log(parseInt(elapsed[0] * 1e3 + elapsed[1] / 1e6));
var startTime = performance.now();// your codeconsole.log(performance.now() - startTime);
Node.js
Browser
![Page 132: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/132.jpg)
Memory usage
122
var mem = process.memoryUsage().heapUsed;// your codeconsole.log(process.memoryUsage().heapUsed - mem);
Очень грубый метод, лучшего простого способа пока нет :'(
![Page 133: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/133.jpg)
Привычные инструменты
![Page 134: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/134.jpg)
devtool
124
Runs Node.js programs inside Chrome DevTools
npm install -g devtool
github.com/Jam3/devtool
![Page 135: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/135.jpg)
> devtool your-script.js
125
![Page 136: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/136.jpg)
Заглядывайте под капот
![Page 137: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/137.jpg)
127
node --trace-hydrogen \ --trace-phase=Z \ --trace-deopt \ --code-comments \ --hydrogen-track-positions \ --redirect-code-traces \ --redirect-code-traces-to=code.asm \ --trace_hydrogen_file=code.cfg \ --print-opt-code \ your-script.js
Получаем данные о работе кода
![Page 139: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/139.jpg)
![Page 140: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/140.jpg)
Самое сложное научиться это понимать ;)
130
![Page 141: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/141.jpg)
Заключение
![Page 142: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/142.jpg)
Вам это все не нужно, но однажды может пригодиться
132
![Page 143: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/143.jpg)
133
• Подбирать решение под задачу
• Меньше тратить памяти
• Меньше мутаций
• Проще структуры
• Разбираться как выполняется код
• Перестать думать, что вы умней VM и наоборот ;)
Капитанские советы
![Page 144: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/144.jpg)
Нет серебряной пули – экспериментируйте, заменяйте,
смотрите под капот
134
![Page 145: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/145.jpg)
Изучайте алгоритмы и структуры данных – правильный их выбор может дать больше
чем оптимизация кода
135
![Page 146: HolyJS - JUG Ru Grouppublic.jugru.org/holyjs/2016/spb/day_1/track_1/dvornov.pdfCSSO — история ускорения Роман Дворнов Avito HolyJS Санкт-Петербург,](https://reader034.fdocument.pub/reader034/viewer/2022042300/5eca7bece531530dd3201b21/html5/thumbnails/146.jpg)
Роман Дворнов @rdvornov
Вопросы?
github.com/css/csso