Первая часть статьи: ссылка
Тест кейсы
Итак, как эти техники сжатия покажут себя в реальном мире?
Я посетил сайты из списка Alexa top 50 (по трафику), чтоб посмотреть, какие из них используют UserTiming (как оказалось, немногие). Я собрал все доступные данные и создал тест кейсы. Набралось 20 реальных и придуманных примеров использования UserTiming.
Давайте сначала сравним JSON.stringify() с лучшей из трех наших техник (для этого конкретного теста будет лучшей своя техника):
+------------------------------+ ¦ Test ¦ JSON ¦ UTC ¦ UTC % ¦ +---------+------+-----+-------¦ ¦ 01.json ¦ 415 ¦ 66 ¦ 16% ¦ +---------+------+-----+-------¦ ¦ 02.json ¦ 196 ¦ 11 ¦ 6% ¦ +---------+------+-----+-------¦ ¦ 03.json ¦ 521 ¦ 18 ¦ 3% ¦ +---------+------+-----+-------¦ ¦ 04.json ¦ 217 ¦ 36 ¦ 17% ¦ +---------+------+-----+-------¦ ¦ 05.json ¦ 364 ¦ 66 ¦ 18% ¦ +---------+------+-----+-------¦ ¦ 06.json ¦ 334 ¦ 43 ¦ 13% ¦ +---------+------+-----+-------¦ ¦ 07.json ¦ 460 ¦ 43 ¦ 9% ¦ +---------+------+-----+-------¦ ¦ 08.json ¦ 91 ¦ 20 ¦ 22% ¦ +---------+------+-----+-------¦ ¦ 09.json ¦ 749 ¦ 63 ¦ 8% ¦ +---------+------+-----+-------¦ ¦ 10.json ¦ 103 ¦ 32 ¦ 31% ¦ +---------+------+-----+-------¦ ¦ 11.json ¦ 231 ¦ 20 ¦ 9% ¦ +---------+------+-----+-------¦ ¦ 12.json ¦ 232 ¦ 19 ¦ 8% ¦ +---------+------+-----+-------¦ ¦ 13.json ¦ 172 ¦ 34 ¦ 20% ¦ +---------+------+-----+-------¦ ¦ 14.json ¦ 658 ¦ 145 ¦ 22% ¦ +---------+------+-----+-------¦ ¦ 15.json ¦ 89 ¦ 48 ¦ 54% ¦ +---------+------+-----+-------¦ ¦ 16.json ¦ 415 ¦ 33 ¦ 8% ¦ +---------+------+-----+-------¦ ¦ 17.json ¦ 196 ¦ 18 ¦ 9% ¦ +---------+------+-----+-------¦ ¦ 18.json ¦ 196 ¦ 8 ¦ 4% ¦ +---------+------+-----+-------¦ ¦ 19.json ¦ 228 ¦ 50 ¦ 22% ¦ +---------+------+-----+-------¦ ¦ 20.json ¦ 651 ¦ 38 ¦ 6% ¦ +---------+------+-----+-------¦ ¦ Total ¦ 6518 ¦ 811 ¦ 12% ¦ +------------------------------+ Легенда: * JSON = JSON.stringify(UserTiming).length (байты) * UTC = Applying UserTimingCompression (байты) * UTC % = UTC байт / JSON байт |
Неплохо, не так ли? В среднем данные сжаты до 12%. Более того, результат является URI-совместимым.
UserTiming-Compression.js
usertiming-compression.js (и его дополнение usertiming-decompression.js) оформлены в виде open-source модулей JavaScript. Их можно скачать тут: ссылка
Предполагается, что эти скрипты предоставят простой способ упаковки данных от UserTiming. Они выбирают один из трех методов — тот, который в данном случае наиболее эффективен.
Если у вас есть детальное понимание используемых в проекте меток и измерений времени, закономерностей в именах и пр, то вероятно вы сможете создать еще более эффективную структуру для передачи данных. Вы также можете изменить скрипт так, что для сжатия всегда будет использоваться один и тот же метод (самый оптимальный).
Сравнение с Gzip / Deflate
Стоп. Почему мы изобретали велосипед, имея под рукой готовые алгоритмы сжатия? Почему не стали сжимать JSON с помощью gzip?
Одна из причин: в JavaScript нет нативной поддержки gzip. Но можно использовать open-source-ную библиотеку вроде pako
Сравним наши техники с результатами gzip:
+----------------------------------------------------+ ¦ Test ¦ JSON ¦ UTC ¦ UTC % ¦ JSON.gz ¦ JSON.gz % ¦ +---------+------+-----+-------+---------+-----------¦ ¦ 01.json ¦ 415 ¦ 66 ¦ 16% ¦ 114 ¦ 27% ¦ +---------+------+-----+-------+---------+-----------¦ ¦ 02.json ¦ 196 ¦ 11 ¦ 6% ¦ 74 ¦ 38% ¦ +---------+------+-----+-------+---------+-----------¦ ¦ 03.json ¦ 521 ¦ 18 ¦ 3% ¦ 79 ¦ 15% ¦ +---------+------+-----+-------+---------+-----------¦ ¦ 04.json ¦ 217 ¦ 36 ¦ 17% ¦ 92 ¦ 42% ¦ +---------+------+-----+-------+---------+-----------¦ ¦ 05.json ¦ 364 ¦ 66 ¦ 18% ¦ 102 ¦ 28% ¦ +---------+------+-----+-------+---------+-----------¦ ¦ 06.json ¦ 334 ¦ 43 ¦ 13% ¦ 96 ¦ 29% ¦ +---------+------+-----+-------+---------+-----------¦ ¦ 07.json ¦ 460 ¦ 43 ¦ 9% ¦ 158 ¦ 34% ¦ +---------+------+-----+-------+---------+-----------¦ ¦ 08.json ¦ 91 ¦ 20 ¦ 22% ¦ 88 ¦ 97% ¦ +---------+------+-----+-------+---------+-----------¦ ¦ 09.json ¦ 749 ¦ 63 ¦ 8% ¦ 195 ¦ 26% ¦ +---------+------+-----+-------+---------+-----------¦ ¦ 10.json ¦ 103 ¦ 32 ¦ 31% ¦ 102 ¦ 99% ¦ +---------+------+-----+-------+---------+-----------¦ ¦ 11.json ¦ 231 ¦ 20 ¦ 9% ¦ 120 ¦ 52% ¦ +---------+------+-----+-------+---------+-----------¦ ¦ 12.json ¦ 232 ¦ 19 ¦ 8% ¦ 123 ¦ 53% ¦ +---------+------+-----+-------+---------+-----------¦ ¦ 13.json ¦ 172 ¦ 34 ¦ 20% ¦ 112 ¦ 65% ¦ +---------+------+-----+-------+---------+-----------¦ ¦ 14.json ¦ 658 ¦ 145 ¦ 22% ¦ 217 ¦ 33% ¦ +---------+------+-----+-------+---------+-----------¦ ¦ 15.json ¦ 89 ¦ 48 ¦ 54% ¦ 91 ¦ 102% ¦ +---------+------+-----+-------+---------+-----------¦ ¦ 16.json ¦ 415 ¦ 33 ¦ 8% ¦ 114 ¦ 27% ¦ +---------+------+-----+-------+---------+-----------¦ ¦ 17.json ¦ 196 ¦ 18 ¦ 9% ¦ 81 ¦ 41% ¦ +---------+------+-----+-------+---------+-----------¦ ¦ 18.json ¦ 196 ¦ 8 ¦ 4% ¦ 74 ¦ 38% ¦ +---------+------+-----+-------+---------+-----------¦ ¦ 19.json ¦ 228 ¦ 50 ¦ 22% ¦ 103 ¦ 45% ¦ +---------+------+-----+-------+---------+-----------¦ ¦ 20.json ¦ 651 ¦ 38 ¦ 6% ¦ 115 ¦ 18% ¦ +---------+------+-----+-------+---------+-----------¦ ¦ Total ¦ 6518 ¦ 811 ¦ 12% ¦ 2250 ¦ 35% ¦ +----------------------------------------------------+ Легенда: * JSON = JSON.stringify(UserTiming).length (байт) * UTC = Applying UserTimingCompression (байт) * UTC % = UTC байт / JSON байт * JSON.gz = gzip(JSON.stringify(UserTiming)).length * JSON.gz % = JSON.gz байт / JSON байт |
Как мы видим, gzip неплохо справляется с упаковкой JSON, уменьшая его размер до 35% от первоначального. Однако, наши техники еще эффективнее и дают всего 12% от первоначального размера.
Что если вместо применения gzip к JSON, мы запакуем минимизированную карту с моментами времени? Пример:
[{"duration":0,"entryType":"mark","name":"mark1","startTime":100},{"duration":0,"entryType":"mark","name":"mark1","startTime":150},{"duration":0,"entryType":"mark","name":"mark1","startTime":500}] |
Что если мы сжали gzip-ом вывод с упакованными моментами времени?
{"mark1":"2s.1e.9q"} |
Вот результаты:
+-----------------------------------+ ¦ Test ¦ UTC ¦ UTC.gz ¦ UTC.gz % ¦ +---------+-----+--------+----------¦ ¦ 01.json ¦ 66 ¦ 62 ¦ 94% ¦ +---------+-----+--------+----------¦ ¦ 02.json ¦ 11 ¦ 24 ¦ 218% ¦ +---------+-----+--------+----------¦ ¦ 03.json ¦ 18 ¦ 28 ¦ 156% ¦ +---------+-----+--------+----------¦ ¦ 04.json ¦ 36 ¦ 46 ¦ 128% ¦ +---------+-----+--------+----------¦ ¦ 05.json ¦ 66 ¦ 58 ¦ 88% ¦ +---------+-----+--------+----------¦ ¦ 06.json ¦ 43 ¦ 43 ¦ 100% ¦ +---------+-----+--------+----------¦ ¦ 07.json ¦ 43 ¦ 60 ¦ 140% ¦ +---------+-----+--------+----------¦ ¦ 08.json ¦ 20 ¦ 33 ¦ 165% ¦ +---------+-----+--------+----------¦ ¦ 09.json ¦ 63 ¦ 76 ¦ 121% ¦ +---------+-----+--------+----------¦ ¦ 10.json ¦ 32 ¦ 45 ¦ 141% ¦ +---------+-----+--------+----------¦ ¦ 11.json ¦ 20 ¦ 37 ¦ 185% ¦ +---------+-----+--------+----------¦ ¦ 12.json ¦ 19 ¦ 35 ¦ 184% ¦ +---------+-----+--------+----------¦ ¦ 13.json ¦ 34 ¦ 40 ¦ 118% ¦ +---------+-----+--------+----------¦ ¦ 14.json ¦ 145 ¦ 112 ¦ 77% ¦ +---------+-----+--------+----------¦ ¦ 15.json ¦ 48 ¦ 45 ¦ 94% ¦ +---------+-----+--------+----------¦ ¦ 16.json ¦ 33 ¦ 50 ¦ 152% ¦ +---------+-----+--------+----------¦ ¦ 17.json ¦ 18 ¦ 37 ¦ 206% ¦ +---------+-----+--------+----------¦ ¦ 18.json ¦ 8 ¦ 23 ¦ 288% ¦ +---------+-----+--------+----------¦ ¦ 19.json ¦ 50 ¦ 53 ¦ 106% ¦ +---------+-----+--------+----------¦ ¦ 20.json ¦ 38 ¦ 51 ¦ 134% ¦ +---------+-----+--------+----------¦ ¦ Total ¦ 811 ¦ 958 ¦ 118% ¦ +-----------------------------------+ Легенда: * UTC = Applying full UserTimingCompression (байт) * TS.gz = gzip(UTC timestamp compression).length * TS.gz % = TS.gz байт / UTC байт |
Даже если применить gzip к результатам timestamp сжатия и потом упаковать gzip-ом результат, наши техники оказываются более эффективными. Результат gzip в среднем на 18% больше. В некоторых тестах gzip работает эффективнее, очевидно, в них много повторяющихся строк.
Надо упомянуть, что использование gzip требует включения сторонней библиотеки вроде pako, а ее размер 26.3 Кбайт. Скрипт usertiming-compression.js намного меньше — 3.9 Кбайт.
Наконец, при использовании gzip сжатия не получится передать строку в строке запроса, т.к. алгоритм URI encode значительно увеличит ее размер из-за экранирования.
Сравнение с MessagePack
MessagePack — это еще один интересный метод упаковки. Девиз проекта: “It’s like JSON. But fast and small“. MessagePack работает с любыми JSON и является переносимым.
Какие результаты он покажет на наших тестах?
Первоначальный JSON он пережимает до 72%. Неплохо для библиотеки, которая нацелена вообще на любой JSON, но плоховато в сравнении с нашими техниками. Одна из причин в том, что MP сохраняет для каждого объекта повторяющиеся строки (startTime, duration ).
+--------------------------------------------------------+ ¦ ¦ JSON ¦ UTC ¦ UTC % ¦ JSON.pack ¦ JSON.pack % ¦ +---------+------+-----+-------+-----------+-------------¦ ¦ Total ¦ 6518 ¦ 811 ¦ 12% ¦ 4718 ¦ 72% ¦ +--------------------------------------------------------+ Легенда: * UTC = Applying UserTimingCompression (bytes) * UTC % = UTC bytes / JSON bytes * JSON.pack = MsgPack(JSON.stringify(UserTiming)).length * JSON.pack % = TS.pack bytes / UTC bytes |
А что если пропустить через MessagePack упакованные timestamp? (например, {«mark1″:»2s.1e.9q», …})
+---------------------------------------+ ¦ Test ¦ UTC ¦ TS.pack ¦ TS.pack % ¦ +---------+-----+----------+------------¦ ¦ 01.json ¦ 66 ¦ 73 ¦ 111% ¦ +---------+-----+----------+------------¦ ¦ 02.json ¦ 11 ¦ 12 ¦ 109% ¦ +---------+-----+----------+------------¦ ¦ 03.json ¦ 18 ¦ 19 ¦ 106% ¦ +---------+-----+----------+------------¦ ¦ 04.json ¦ 36 ¦ 43 ¦ 119% ¦ +---------+-----+----------+------------¦ ¦ 05.json ¦ 66 ¦ 76 ¦ 115% ¦ +---------+-----+----------+------------¦ ¦ 06.json ¦ 43 ¦ 44 ¦ 102% ¦ +---------+-----+----------+------------¦ ¦ 07.json ¦ 43 ¦ 43 ¦ 100% ¦ +---------+-----+----------+------------¦ ¦ 08.json ¦ 20 ¦ 21 ¦ 105% ¦ +---------+-----+----------+------------¦ ¦ 09.json ¦ 63 ¦ 63 ¦ 100% ¦ +---------+-----+----------+------------¦ ¦ 10.json ¦ 32 ¦ 33 ¦ 103% ¦ +---------+-----+----------+------------¦ ¦ 11.json ¦ 20 ¦ 21 ¦ 105% ¦ +---------+-----+----------+------------¦ ¦ 12.json ¦ 19 ¦ 20 ¦ 105% ¦ +---------+-----+----------+------------¦ ¦ 13.json ¦ 34 ¦ 33 ¦ 97% ¦ +---------+-----+----------+------------¦ ¦ 14.json ¦ 145 ¦ 171 ¦ 118% ¦ +---------+-----+----------+------------¦ ¦ 15.json ¦ 48 ¦ 31 ¦ 65% ¦ +---------+-----+----------+------------¦ ¦ 16.json ¦ 33 ¦ 40 ¦ 121% ¦ +---------+-----+----------+------------¦ ¦ 17.json ¦ 18 ¦ 21 ¦ 117% ¦ +---------+-----+----------+------------¦ ¦ 18.json ¦ 8 ¦ 11 ¦ 138% ¦ +---------+-----+----------+------------¦ ¦ 19.json ¦ 50 ¦ 52 ¦ 104% ¦ +---------+-----+----------+------------¦ ¦ 20.json ¦ 38 ¦ 40 ¦ 105% ¦ +---------+-----+----------+------------¦ ¦ Total ¦ 811 ¦ 867 ¦ 107% ¦ +---------------------------------------+ Легенда: * UTC = Applying full UserTimingCompression (байт) * TS.pack = MsgPack(UTC timestamp compression).length * TS.pack % = TS.pack байт / UTC байт |
Для 20 тестов результат MessagePack на 7% больше результатов наших методик.
Размер популярных библиотек MessagePack тоже кусается: 29.2, 36.9 и 104 Кбайт.
Если у вас есть хорошее понимание закономерностей в ваших данных, то собственный алгоритм сжатия может быть более эффективным по сравнению с общепринятыми вроде gzip или MessagePack.
Выводы
Бывает интересно изучить нужную в работе структуру данных и сжать ее насколько это возможно.
UserTiming — это могучий и недооцененный API. Если вы его уже используете, то наверно уже решили задачу упаковки данных при передаче. Если нет, данная заметка вам поможет.
Английский оригинал: оригинал статьи
Документация и полезные ссылки:
UserTiming W3C Specification
PerformanceTimeline W3C Specification
UserTiming in Practice
Steve Souders’ UserTiming and Custom Metrics
ResourceTiming in Practice
Compressing ResourceTiming