SlideShare a Scribd company logo
Парсим CSS
performance tips & tricks
Роман Дворнов
Avito
Москва, сентябрь 2016
Руководитель 

фронтенда в Avito
Основной интерес – SPA
Open source:

basis.js, CSSO, 

component-inspector, 

csstree и другие
За любую движуху, 

кроме голодовки ;)
Парсим CSS
(зачем? почему? как дальше жить?)
3
tinyurl.com/csstree-intro
Начало истории (доклад)
CSSTree
CSSTree – самый быстрый 

и детальный парсер CSS
5
Как я до этого докатился?
Чуть меньше года назад 

я стал мейнтейнером CSSO
(минификатор CSS)
7
github.com/css/csso
CSSO работал на основе
парсера Gonzales
8
github.com/css/gonzales
Проблемы
• Не развивается с 2013
• Неудобный формат AST, местами странный
• Много ошибок
• Запутанная и сложная кодовая база
• Медленный, потребляет много памяти, GC
9
Парсер – последнее, что я
собирался трогать…
10
Альтернатива?
Парсеров CSS на JavaScript
достаточно много
12
Частые проблемы
• Заброшены и не развиваются
• Устарели (не поддерживают новое в CSS)
• Содержат ошибки
• Неудачная структура
• Медленные
13
Наилучшим выбором может
быть парсер из PostCSS
14
postcss.org
Плюсы PostCSS
• Развивается и поддерживается
• Хорошо справляется с синтаксисом CSS и даже
будущим + tolerant mode
• Сохраняет информацию о форматировании
• Удобное API для работы с AST
• Быстрый
15
Основная проблема:
селекторы и значения свойств
остаются не разобранными
(хранятся в виде строки)
16
Это вынуждает разработчиков
• Использовать костыли
• Писать свои парсеры
• Использовать дополнительные парсеры:

postcss-selector-parser

postcss-value-parser
17
Переход на PostCSS означал написание
собственных парсеров селекторов и
свойств, что не сильно отличается от
написания парсера целиком
18
Регулярный рефакторинг приводит к тому,
что парсер может быть полностью переписан 

(это норма 😳)
19
Парсер выделен в отдельный проект
github.com/csstree/csstree
20
Скорость
CSSO – история ускорения
(в том числе про парсер)
22
tinyurl.com/csso-speedup
В предыдущих сериях (доклад)
После выступления разогнал
парсер еще :)
23
* Вдохновленный общением с Вячеславом @mraleph Егоровым
24
CSSTree: 24 ms
Mensch: 31 ms
CSSOM: 36 ms
PostCSS: 38 ms
Rework: 81 ms
PostCSS Full: 100 ms
Gonzales: 175 ms
Stylecow: 176 ms
Gonzales PE: 214 ms
ParserLib: 414 ms
bootstrap.css v3.3.7 (146Kb)
github.com/postcss/benchmark
Не детальное AST
Детальное AST
PostCSS Full =
+ postcss-selector-parser
+ postcss-value-parser
Epic fail
как выяснилось позже, я вынес
не ту версию парсера
25
😱
github.com/csstree/csstree/commit/57568c758195153e337f6154874c3bc42dd04450
26
CSSTree: 24 ms
Mensch: 31 ms
CSSOM: 36 ms
PostCSS: 38 ms
Rework: 81 ms
PostCSS Full: 100 ms
Gonzales: 175 ms
Stylecow: 176 ms
Gonzales PE: 214 ms
ParserLib: 414 ms
bootstrap.css v3.3.7 (146Kb)
github.com/postcss/benchmark
На FrontTalks был
показан результат
до разгона
13 ms
Парсеры: курс молодого бойца
Основные шаги
• Токенизация
• Построение дерева (лексер)
28
Токенизация
30
• whitespaces – [ nrtf]+
• keyword – [a-zA-aZ…]+
• number – [0-9]+
• string – "string" или 'string'
• comment – /* comment */
• punctuation – [;,.#{}[]()…]
Разбиение текста на токены
31
.foo {
width: 10px;
}
[
'.', 'foo', ' ', '{',
'n ', 'width', ':',
' ', '10', 'px', ';',
'n', '}'
]
Нужна дополнительная информация
о токене: тип и локация
32
На этапе токенизации мы
знаем тип и позицию,
считать их после – дорого
33
.foo {
width: 10px;
}
[
{
type: 'FullStop',
value: '.',
offset: 0,
line: 1,
column: 1
},
…
]
Сборка
35
function getSelector() {
var selector = {
type: 'Selector',
sequence: []
};
// main loop
return selector;
}
Сборка
36
for (;currentToken < tokenCount; currentToken++) {
switch (tokens[currentToken]) {
case TokenType.Hash: // #
selector.sequence.push(getId());
break;
case TokenType.FullStop: // .
selector.sequence.push(getClass());
break;
…
}
Main loop
37
{
"type": "StyleSheet",
"rules": [{
"type": "Atrule",
"name": "import",
"expression": {
"type": "AtruleExpression",
"sequence": [ ... ]
},
"block": null
}]
}
Результат
История ускорения #2
39
[
{
type: 'FullStop',
value: '.',
offset: 0,
line: 1,
column: 1
},
…
]
Стоимость токена:
24 + 5 * 4 + массив =
min 50 bytes per token
В нашем проекте ~1Mb CSS
254 062 токена
=
min 12.7 Mb
Прелюдия: меняем подход
Посчитать все токены, а потом 

из них собирать AST – проще,
но ведет к лишним затратам памяти
и медленней
41
Scanner
(ленивый токенайзер)
42
43
scanner.token // текущий токен или null
scanner.next() // переход к следующему токену
scanner.lookup(N) // заглядывание вперед, возвращает
// токен на N-ой позиции от текущей
Основное API
44
• lookup(N)

заполняет буфер токенов до позиции N, если еще
не заполнен, возвращает N-1 токен из буфера
• next()

делает shift из lookup буфера, если он не пустой,
либо читает новый токен
Создается столько же токенов, 

но нужно меньше памяти в один
момент времени
45
Проблема:
заставляем CG плакать работать
46
Уменьшаем стоимость токенов:
«многоходовочка»
48
[
{
type: 'FullStop',
value: '.',
offset: 0,
line: 1,
column: 1
},
…
]
Строковые обозначения
удобны при отладке, но
они не выходят за рамки
сканера и можно
заменить на числа
49
[
{
type: FULLSTOP,
value: '.',
offset: 0,
line: 1,
column: 1
},
…
]
…
// '.'.charCodeAt(0)
var FULLSTOP = 46;
…
50
[
{
type: 46,
value: '.',
offset: 0,
line: 1,
column: 1
},
…
]
51
[
{
type: 46,
value: '.',
offset: 0,
line: 1,
column: 1
},
…
]
Можно не хранить
подстроку – это особенно
расточительно для
одиночных символов;
к тому же многие многие
конструкции собираются
из нескольких токенов –
эффективнее брать одну
подстроку вместо
конкатенации нескольких
52
[
{
type: 46,
value: '.',
offset: 0,
line: 1,
column: 1
},
…
]
[
{
type: 46,
start: 0,
end: 1,
line: 1,
column: 1
},
…
]
53
[
{
type: 46,
start: 0,
end: 1,
line: 1,
column: 1
},
…
]
Look, Ma!
No strings just numbers!
54
Да не просто Array, а TypedArray
Массив 

объектов
Массивы 

чисел
Array vs. TypedArray
• Не могут содержать дырок
• В теории быстрее (т.к. меньше проверок)
• Хранятся вне heap (если достаточно большие)
• Предзаполнены нулями
55
56
[
{
type: 46,
start: 0,
end: 1,
line: 1,
column: 1
},
…
]
Uint8Array
Uint32Array
Uint32Array
Uint32Array
Uint32Array
1
4
4
4
4
17 per token
(кол-во токенов) 254 062 x 17 = 4.3Mb
4.3Mb vs. 12.7Mb(min)
57
Хьюстон, у нас проблемы:
TypedArray фиксированной длины,

а мы не знаем сколько токенов будет
58
59
[
{
type: 46,
start: 0,
end: 1,
line: 1,
column: 1
},
…
]
Uint8Array
Uint32Array
Uint32Array
Uint32Array
Uint32Array
1
4
4
4
4
17 per token
(кол-во символов) 983 085 x 17 = 16.7Mb
16.7Mb vs. 12.7Mb (min)
60
16.7Mb vs. 12.7Mb (min)
60
Не повод сдаваться, 

давайте немного
подумаем…
61
start = [ 0, 5, 6, 7, 9, 11, …, 35 ]
end = [ 5, 6, 7, 9, 11, 12, …, 36 ]
61
start = [ 0, 5, 6, 7, 9, 11, …, 35 ]
end = [ 5, 6, 7, 9, 11, 12, …, 36 ]
…
62
start = [ 0, 5, 6, 7, 9, 11, …, 35 ]
end = [ 5, 6, 7, 9, 11, 12, …, 36 ]
offset = [ 0, 5, 6, 7, 9, 11, …, 35, 36 ]
start = offset[i]
end = offset[i + 1]
+
=
63
[
{
type: 46,
start: 0,
end: 1,
line: 1,
column: 1
},
…
]
Uint8Array
Uint32Array
Uint32Array
Uint32Array
Uint32Array
1
4
4
4
4
13 per token
983 085 x 13 = 12.7Mb
64
a {
top: 0;
}
lines = [
1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3
]
columns = [
1, 2, 3, 4,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
1
]
lines & columns
64
a {
top: 0;
}
lines = [
1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3
]
columns = [
1, 2, 3, 4,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
1
]
lines & columns
65
line = lines[offset];
column = offset - lines.lastIndexOf(line - 1, offset);
lines & columns
65
line = lines[offset];
column = offset - lines.lastIndexOf(line - 1, offset);
lines & columns
Ок для коротких строк,
нужно кешировать для
длинных
66
[
{
type: 46,
start: 0,
end: 1,
line: 1,
column: 1
},
…
]
Uint8Array
Uint32Array
Uint32Array
Uint32Array
Uint32Array
1
4
4
4
4
9 per token
983 085 x 9 = 8.8Mb
67
8.8Mb vs. 12.7Mb(min)
Меньше операций со строками
«Убийцы» производительности*
• RegExp
• Конкатенация строк
• toLowerCase/toUpperCase
• substr/substring
• …
69
* Засоряют GC и он все портит
«Убийцы» производительности*
• RegExp
• Конкатенация строк
• toLowerCase/toUpperCase
• substr/substring
• …
70
Без этого никак, 

но от остального
можно избавиться
* Засоряют GC и он все портит
71
var start = scanner.tokenStart;
…
scanner.next();
…
scanner.next();
…
return source.substr(start, scanner.tokenEnd);
Нет конкатенации!
72
function cmpStr(source, start, end, str) {
if (end - start !== str.length) {
return false;
}
for (var i = start; i < end; i++) {
var sourceCode = source.charCodeAt(i);
var strCode = str.charCodeAt(i - start);
if (sourceCode !== strCode) {
return false;
}
}
return true;
}
Сравнение строк
73
function cmpStr(source, start, end, str) {
if (end - start !== str.length) {
return false;
}
for (var i = start; i < end; i++) {
var sourceCode = source.charCodeAt(i);
var strCode = str.charCodeAt(i - start);
if (sourceCode !== strCode) {
return false;
}
}
return true;
}
Сравнение строк
Быстрое отсечение
по длине
74
function cmpStr(source, start, end, str) {
if (end - start !== str.length) {
return false;
}
for (var i = start; i < end; i++) {
var sourceCode = source.charCodeAt(i);
var strCode = str.charCodeAt(i - start);
if (sourceCode !== strCode) {
return false;
}
}
return true;
}
Сравнение строк
Сравниваем 

код за кодом
Как сравнивать 

без учета регистра*?
75
* То есть без toLowerCase/toUpperCase
Эвристика
• Сравниваем с заранее известными строками (str)
• Заранее заданные строки всегда в нижнем
регистре и содержат только латинские буквы
• Читал я как то в твиттере…
76
Чтобы перевести из верхнего регистра в
нижний, нужно выставить 6-й бит в 1
(работает только для латинских букв)
'A' = 01000001
'a' = 01100001
'A'.charCodeAt(0) | 32 === 'a'.charCodeAt(0)
77
78
function cmpStr(source, start, end, str) {
…
for (var i = start; i < end; i++) {
…
// source[i].toLowerCase()
if (sourceCode >= 65 && sourceCode <= 90) { // 'A' .. 'Z'
sourceCode = sourceCode | 32;
}
if (sourceCode !== strCode) {
return false;
}
}
…
}
Сравнение строк без учета регистра
Бенефиты
• Часто срабатывает быстрое отсечение
• Нет получения подстрок (не давим на CG)
• Нет получения временных строк 

(результат toLowerCase/toUpperCase)
• Операция сравнения не производит мусор
79
Отказываемся от массивов
(от слова совсем)
Что не так с массивами
• Если растить массив, то происходит
копирование памяти + нагрузка на GC
• Мы не можем заранее знать размер массива
81
Решение?
82
Двусвязные списки
83
84
Плюсы
• Не вызывает копирование памяти
• Не засоряет CG при построении AST
• Мы получаем next/prev
85
Всё это и многое другое позволило
уменьшить потребление памяти,
нагрузку на GC 

и ускорить вдвое
86
Но это еще не конец 😋
87
История ускорения #3
неделя после FrontTalks
Общие моменты
• Упрощение структуры AST
• Меньше потребление памяти, переиспользование
• list.map().join() -> цикл + конкатенация
• и по мелочи…
89
И снова про стоимость токенов
91
[
{
type: 46,
start: 0,
end: 1,
line: 1,
column: 1
},
…
]
Uint8Array
Uint32Array
Uint32Array
Uint32Array
Uint32Array
1 types
4 offsets
4
4 lines
4
9 per token
983 085 x 9 = 8.8Mb
lines можно считать не всегда и лениво
92
93
[
{
type: 46,
start: 0,
end: 1,
line: 1,
column: 1
},
…
]
Uint8Array
Uint32Array
Uint32Array
Uint32Array
Uint32Array
1 types
4 offsets
4
4 lines
4
5 per token
983 085 x 5 = 4.9Mb
Действительно ли для offsets
нужно 32 бита?
Эвристика: вряд ли кто-то будет парсить
CSS больше 16Mb
94
95
offset = [ 0, 5, 6, 7, 9, 11, 11, …, 1234 ]
type = [ 1, 47, 47, 4, 4, 47, 5, …, 3 ]
96
offset = [ 0, 5, 6, 7, 9, 11, 11, …, 1234 ]
type = [ 1, 47, 47, 4, 4, 47, 5, …, 3 ]
offsetAndType[i] = type[i] << 24 | offset[i]
+
=
97
offset = [ 0, 5, 6, 7, 9, 11, 11, …, 1234 ]
type = [ 1, 47, 47, 4, 4, 47, 5, …, 3 ]
offsetAndType[i] = type[i] << 24 | offset[i]
offsetAndType = [ 16777216, 788529157, … ]
+
=
98
offset = [ 0, 5, 6, 7, 9, 11, 11, …, 1234 ]
type = [ 1, 47, 47, 4, 4, 47, 5, …, 3 ]
offsetAndType[i] = type[i] << 24 | offset[i]
offsetAndType = [ 16777216, 788529157, … ]
offset = offsetAndType[i] & 0xFFFFFF;
type = offsetAndType[i] >> 24;
+
=
99
[
{
type: 46,
start: 0,
end: 1,
line: 1,
column: 1
},
…
]
Uint8Array
Uint32Array
Uint32Array
Uint32Array
Uint32Array
1 types
4 offsets
4
4 lines
4
4 per token
983 085 x 4 = 3.9Mb
3.9-7.8 Mb vs. 12.7 Mb (min)
100
101
class Scanner {
...
next() {
var next = this.currentToken + 1;
this.currentToken = next;
this.tokenStart = this.tokenEnd;
this.tokenEnd = this.offsetAndType[next + 1] & 0xFFFFFF;
this.tokenType = this.offsetAndType[next] >> 24;
}
}
Два чтения из массива – 

как то не круто…
102
offset = [ 0, 5, 6, 7, 9, 11, 11, …, 1234 ]
type = [ 1, 47, 47, 4, 4, 47, 5, …, 3 ]
103
offset = [ 0, 5, 6, 7, 9, 11, 11, …, 1234 ]
type = [ 0, 1, 47, 47, 4, 4, 47, 5, …, 3 ]
103
offset = [ 0, 5, 6, 7, 9, 11, 11, …, 1234 ]
type = [ 0, 1, 47, 47, 4, 4, 47, 5, …, 3 ]
…
104
class Scanner {
...
next() {
var next = this.currentToken + 1;
this.currentToken = next;
this.tokenStart = this.tokenEnd;
this.tokenEnd = this.offsetAndType[next + 1] & 0xFFFFFF;
this.tokenType = this.offsetAndType[next + 1] >> 24;
}
}
Теперь можно в одно
чтение
105
class Scanner {
...
next() {
var next = this.currentToken + 1;
this.currentToken = next;
this.tokenStart = this.tokenEnd;
next = this.offsetAndType[next + 1];
this.tokenEnd = next & 0xFFFFFF;
this.tokenType = next >> 24;
}
}
-50% чтений (~250k)
Переиспользование
Сканер каждый раз создавал
новые массивы на каждый
разбор
107
Сканер каждый раз создавал
новые массивы на каждый
разбор
107
Новая стратегия
• По дефолту создается буфер в 16Kb
• Создается новый буфер, только если он мал
для разбираемого CSS
• Значительный прирост скорости, особенно в
сценариях разбора малых фрагментов CSS
108
109
CSSTree: 24 ms
Mensch: 31 ms
CSSOM: 36 ms
PostCSS: 38 ms
Rework: 81 ms
PostCSS Full: 100 ms
Gonzales: 175 ms
Stylecow: 176 ms
Gonzales PE: 214 ms
ParserLib: 414 ms
bootstrap.css v3.3.7 (146Kb)
github.com/postcss/benchmark
13 ms 7 ms
Текущий результат
И это еще не конец… 😋
110
Минутка «рекламы»
CSSTree – 

не только про скорость
112
Новая фича*:
Разбор и матчинг синтаксиса
CSS значений
113
* Пока уникальная среди CSS парсеров
Пример
114
115
csstree.github.io/docs/syntax.html
Документация синтаксиса
116
csstree.github.io/docs/validator.html
Валидатор синтаксиса CSS значений
117
var csstree = require('css-tree');
var syntax = csstree.syntax.defaultSyntax;
var ast = csstree.parse('… your css …');
csstree.walkDeclarations(ast, function(node) {
if (!syntax.match(node.property.name, node.value)) {
console.log(syntax.lastMatchError);
}
});
Свой валидатор в 8 строк
Кое что еще
• csstree-validator – npm пакет + консольная команда
• stylelint-csstree-validator – плагин для stylelint
• gulp-csstree – плагин для gulp
• SublimeLinter-contrib-csstree – плагин для Sublime Text
• vscode-csstree – плагин для VS Code
• csstree-validator – плагин для Atom



More is coming…
118
Заключение
Хотите чтобы ваш JavaScript
работал так же быстро как Си,
сделайте его похожим на Си
120
Изучайте алгоритмы, структуры данных,
как работают JS-движки и GC – 

у вас будет больше вариантов для
оптимизаций
121
– К.О.
Доклады по теме
• CSSO – история ускорения

tinyurl.com/csso-speedup
• Парсим CSS

tinyurl.com/csstree-intro
122
github.com/csstree/csstree
123
Нужен ваш фидбек
Роман Дворнов
@rdvornov
github.com/lahmatiy
rdvornov@gmail.com
Вопросы?
github.com/csstree/csstree

More Related Content

What's hot (20)

PPTX
Developing highload servers with Java
Andrei Pangin
 
PDF
Как впихнуть утро в сосновом лесу в 4 килобайта. Иван Авдеев. UNIGINE Open Ai...
Unigine Corp.
 
ODP
Boost.Algorithm: что, зачем и почему
corehard_by
 
PDF
Функционально декларативный дизайн на C++
Alexander Granin
 
PPT
Основы индексирования и расширенные возможности EXPLAIN в MySQL / Василий Лук...
Ontico
 
PDF
CSSO — минимизируем CSS
Roman Dvornov
 
PDF
хитрости выведения типов
corehard_by
 
PDF
Clojure – есть ли жизнь после Java
Olim Saidov
 
PPTX
Ruby - или зачем мне еще один язык программирования?
Pavel Tsukanov
 
PDF
Clojure #2 (2014)
Alexander Podkhalyuzin
 
PDF
Clojure #1
Alexander Podkhalyuzin
 
PDF
Haskell
DevDay
 
PDF
Сверхоптимизация кода на Python
ru_Parallels
 
PPTX
Deep Dive C# by Sergey Teplyakov
Alex Tumanoff
 
PDF
Pyton – пробуем функциональный стиль
Python Meetup
 
PDF
Something about Golang
Anton Arhipov
 
PDF
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...
Alexey Paznikov
 
PPTX
Async clinic by by Sergey Teplyakov
Alex Tumanoff
 
PDF
Java 8 puzzlers
Evgeny Borisov
 
PDF
Инструменты для з̶а̶х̶в̶а̶т̶а̶ ̶м̶и̶р̶а̶ отладки в Tarantool
Timur Safin
 
Developing highload servers with Java
Andrei Pangin
 
Как впихнуть утро в сосновом лесу в 4 килобайта. Иван Авдеев. UNIGINE Open Ai...
Unigine Corp.
 
Boost.Algorithm: что, зачем и почему
corehard_by
 
Функционально декларативный дизайн на C++
Alexander Granin
 
Основы индексирования и расширенные возможности EXPLAIN в MySQL / Василий Лук...
Ontico
 
CSSO — минимизируем CSS
Roman Dvornov
 
хитрости выведения типов
corehard_by
 
Clojure – есть ли жизнь после Java
Olim Saidov
 
Ruby - или зачем мне еще один язык программирования?
Pavel Tsukanov
 
Clojure #2 (2014)
Alexander Podkhalyuzin
 
Haskell
DevDay
 
Сверхоптимизация кода на Python
ru_Parallels
 
Deep Dive C# by Sergey Teplyakov
Alex Tumanoff
 
Pyton – пробуем функциональный стиль
Python Meetup
 
Something about Golang
Anton Arhipov
 
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...
Alexey Paznikov
 
Async clinic by by Sergey Teplyakov
Alex Tumanoff
 
Java 8 puzzlers
Evgeny Borisov
 
Инструменты для з̶а̶х̶в̶а̶т̶а̶ ̶м̶и̶р̶а̶ отладки в Tarantool
Timur Safin
 

Viewers also liked (20)

PDF
Что надо знать о HTTP/2
Badoo Development
 
PDF
S.O.L.I.D-ый JavaScript
Badoo Development
 
PDF
Классическое программирование для фронтендеров
Badoo Development
 
PDF
Как мы общаемся с пользователями на 46 языках и понимаем друг друга
Badoo Development
 
PPTX
Багфиксинг процесса разработки в iOS: взгляд с двух сторон
Badoo Development
 
PDF
Мобильный веб: назад в будущее
Badoo Development
 
PDF
Технологии vs коммуникации: что важнее?
Badoo Development
 
PDF
Как автотесты ускоряют релизы в OK.ru
Badoo Development
 
PDF
TechLeads meetup: Макс Лапшин, Erlyvideo
Badoo Development
 
PPTX
TechLeads meetup: Андрей Шелёхин, Tinkoff.ru
Badoo Development
 
PDF
Profiling and optimizing go programs
Badoo Development
 
PDF
Семь тысяч Rps, один go
Badoo Development
 
PDF
"Новые возможности MySQL 5.7"
Badoo Development
 
PPTX
"Геолокация в Badoo", Андрей Воликов (Badoo)
Badoo Development
 
PDF
"Обзор Tarantool DB"
Badoo Development
 
PDF
«Миллион открытых каналов с данными по сети» – Илья Биин (Zenhotels)
AvitoTech
 
PDF
"PostgreSQL для разработчиков приложений", Павел Лузанов, (Постгрес Профессио...
Badoo Development
 
PDF
"Производительность MySQL: что нового?"
Badoo Development
 
PPTX
"Великолепный API без Rest", Констатин Якушев (Badoo)
Badoo Development
 
PDF
Golang в avito
AvitoTech
 
Что надо знать о HTTP/2
Badoo Development
 
S.O.L.I.D-ый JavaScript
Badoo Development
 
Классическое программирование для фронтендеров
Badoo Development
 
Как мы общаемся с пользователями на 46 языках и понимаем друг друга
Badoo Development
 
Багфиксинг процесса разработки в iOS: взгляд с двух сторон
Badoo Development
 
Мобильный веб: назад в будущее
Badoo Development
 
Технологии vs коммуникации: что важнее?
Badoo Development
 
Как автотесты ускоряют релизы в OK.ru
Badoo Development
 
TechLeads meetup: Макс Лапшин, Erlyvideo
Badoo Development
 
TechLeads meetup: Андрей Шелёхин, Tinkoff.ru
Badoo Development
 
Profiling and optimizing go programs
Badoo Development
 
Семь тысяч Rps, один go
Badoo Development
 
"Новые возможности MySQL 5.7"
Badoo Development
 
"Геолокация в Badoo", Андрей Воликов (Badoo)
Badoo Development
 
"Обзор Tarantool DB"
Badoo Development
 
«Миллион открытых каналов с данными по сети» – Илья Биин (Zenhotels)
AvitoTech
 
"PostgreSQL для разработчиков приложений", Павел Лузанов, (Постгрес Профессио...
Badoo Development
 
"Производительность MySQL: что нового?"
Badoo Development
 
"Великолепный API без Rest", Констатин Якушев (Badoo)
Badoo Development
 
Golang в avito
AvitoTech
 
Ad

Similar to Парсим CSS (20)

PPTX
JavaScript на сервере, 1ms на трансформацию (Андрей Сумин)
Ontico
 
PPT
Выступление Андрея Сумина, Mail.Ru Group, на High Performance Conference
EYevseyeva
 
PDF
Обзор ES2015(ES6)
Alex Filatov
 
PDF
My Open Source (Sept 2017)
Roman Dvornov
 
PDF
Иван Кочуркин. Теория и практика парсинга формальных языков
MskDotNet Community
 
PDF
"Портирование Web SDK с JS на TS" Петров Григорий, Voximplant
it-people
 
PDF
Макс Ширшин — Регулярные выражения
Yandex
 
PDF
ECMAscript harmony
FDConf
 
PDF
Дополнительные возможности Javascript
Denis Latushkin
 
PDF
Денис Чистяков: DOM, jQuery и все, все, все
Yandex
 
PPT
Подробная презентация JavaScript 6 в 1
Vasya Petrov
 
PDF
Code Style (in russian)
Mikhail Davydov
 
PPTX
course js day 2
Georgyi Grigoryev
 
PDF
React со скоростью света: не совсем обычный серверный рендеринг
Timophy Chaptykov
 
PDF
CSS глазами машин
Roman Dvornov
 
PDF
Лекция 4. Строки, байты, файлы и ввод/вывод.
Roman Brovko
 
PDF
Дэвид Флэнаган — Javascript (5 издание)
mlatushko
 
PDF
Жизнь в изоляции / Роман Дворнов (Avito)
Ontico
 
PPT
Javascript
Vasya Petrov
 
PDF
Avito / SPA Meetup 2
Константин Лебедев
 
JavaScript на сервере, 1ms на трансформацию (Андрей Сумин)
Ontico
 
Выступление Андрея Сумина, Mail.Ru Group, на High Performance Conference
EYevseyeva
 
Обзор ES2015(ES6)
Alex Filatov
 
My Open Source (Sept 2017)
Roman Dvornov
 
Иван Кочуркин. Теория и практика парсинга формальных языков
MskDotNet Community
 
"Портирование Web SDK с JS на TS" Петров Григорий, Voximplant
it-people
 
Макс Ширшин — Регулярные выражения
Yandex
 
ECMAscript harmony
FDConf
 
Дополнительные возможности Javascript
Denis Latushkin
 
Денис Чистяков: DOM, jQuery и все, все, все
Yandex
 
Подробная презентация JavaScript 6 в 1
Vasya Petrov
 
Code Style (in russian)
Mikhail Davydov
 
course js day 2
Georgyi Grigoryev
 
React со скоростью света: не совсем обычный серверный рендеринг
Timophy Chaptykov
 
CSS глазами машин
Roman Dvornov
 
Лекция 4. Строки, байты, файлы и ввод/вывод.
Roman Brovko
 
Дэвид Флэнаган — Javascript (5 издание)
mlatushko
 
Жизнь в изоляции / Роман Дворнов (Avito)
Ontico
 
Javascript
Vasya Petrov
 
Ad

More from Badoo Development (20)

PDF
Viktar Karanevich – iOS Parallel Automation
Badoo Development
 
PDF
Как мы делаем модули PHP в Badoo – Антон Довгаль
Badoo Development
 
PDF
Григорий Джанелидзе, OK.RU
Badoo Development
 
PPTX
Андрей Сидоров, Яндекс.Браузер
Badoo Development
 
PDF
Филипп Уваров, Avito
Badoo Development
 
PDF
Cocoaheads Meetup / Alex Zimin / Swift magic
Badoo Development
 
PDF
Cocoaheads Meetup / Kateryna Trofimenko / Feature development
Badoo Development
 
PDF
Alex Krasheninnikov – Hadoop High Availability
Badoo Development
 
PDF
Андрей Денисов – В ожидании мониторинга баз данных
Badoo Development
 
PDF
Александр Зобнин, Grafana Labs
Badoo Development
 
PDF
Илья Аблеев – Zabbix в Badoo: реагируем быстро и качественно
Badoo Development
 
PDF
TechLeads meetup: Алексей Рыбак, Badoo
Badoo Development
 
PPTX
TechLeads meetup: Евгений Потапов, ITSumma
Badoo Development
 
PDF
Паша Мурзаков: Как 200 строк на Go помогли нам освободить 15 серверов»
Badoo Development
 
PPTX
Как мы готовим MySQL
Badoo Development
 
PPTX
Архитектура хранения и отдачи фотографий в Badoo
Badoo Development
 
PDF
5 способов деплоя PHP-кода в условиях хайлоада
Badoo Development
 
PDF
ChromeDriver Jailbreak
Badoo Development
 
PDF
Git хуки на страже качества кода
Badoo Development
 
PDF
Versioning strategy for a complex internal API
Badoo Development
 
Viktar Karanevich – iOS Parallel Automation
Badoo Development
 
Как мы делаем модули PHP в Badoo – Антон Довгаль
Badoo Development
 
Григорий Джанелидзе, OK.RU
Badoo Development
 
Андрей Сидоров, Яндекс.Браузер
Badoo Development
 
Филипп Уваров, Avito
Badoo Development
 
Cocoaheads Meetup / Alex Zimin / Swift magic
Badoo Development
 
Cocoaheads Meetup / Kateryna Trofimenko / Feature development
Badoo Development
 
Alex Krasheninnikov – Hadoop High Availability
Badoo Development
 
Андрей Денисов – В ожидании мониторинга баз данных
Badoo Development
 
Александр Зобнин, Grafana Labs
Badoo Development
 
Илья Аблеев – Zabbix в Badoo: реагируем быстро и качественно
Badoo Development
 
TechLeads meetup: Алексей Рыбак, Badoo
Badoo Development
 
TechLeads meetup: Евгений Потапов, ITSumma
Badoo Development
 
Паша Мурзаков: Как 200 строк на Go помогли нам освободить 15 серверов»
Badoo Development
 
Как мы готовим MySQL
Badoo Development
 
Архитектура хранения и отдачи фотографий в Badoo
Badoo Development
 
5 способов деплоя PHP-кода в условиях хайлоада
Badoo Development
 
ChromeDriver Jailbreak
Badoo Development
 
Git хуки на страже качества кода
Badoo Development
 
Versioning strategy for a complex internal API
Badoo Development
 

Парсим CSS