От автора: веб-шрифты – это широко используемый метод доступа к шрифтам даже тогда, когда шрифты не установлены на той или иной операционной системе, они позволяют веб-сайтам предоставлять их через отдельные стили. Однако, у веб-шрифтов есть и недостатки, например, снижение производительности, так как загрузка шрифтов занимает много времени из-за проблем с оптимизацией, ограничения по размеру и пропускной способности, независимо от того, с каким клиентом вы работаете.
В результате могут возникнуть такие проблемы:
Чтобы измерить, сколько времени требуется, чтобы каждый шрифт загрузился в документ клиента, нам понадобится Font Loading API. Запустив UserTiming API, можно измерить временные параметры загрузки страницы.
Сниппет
Здесь мы приведем небольшой скрипт, который получает доступ к document.fonts.ready и document.fonts.entries, чтобы измерить, сколько времени нужно для загрузки каждому шрифту по отдельности и всем шрифтам вместе:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
(function(w, d) { /** * Задаем оценку производительности для данного начертания шрифта со стилем, толщиной и растяжением * @param fontFace - FontFace объект, содержащий метаданные имени и стиля */ function fontfacePromiseResolve(fontFace) { window.performance.mark([fontFace.family, fontFace.style, fontFace.weight, fontFace.stretch].join("_")); } /** * Если возникает ошибка, регистрируем ее как Error в консоли * @param err – объект Error */ function exceptionHandling(err) { console.error(err); } // Убеждаемся, что Fonts API и `document.fonts.ready` доступны // Также убеждаемся, что window.performance.mark доступен для оценок UserTiming if (d.fonts && d.fonts.ready && window.performance && typeof window.performance.mark === "function") { try { // fonts.entries() – это итератор, который мы будем использовать, чтобы проследить загрузку каждого шрифта var entries = d.fonts.entries(), valueIndex = 0; for(let entry of entries) { for (valueIndex = 0; valueIndex < entry.length; valueIndex++) { entry[valueIndex].loaded.then(fontfacePromiseResolve).catch(exceptionHandling); } } // document.fonts.ready – мы подключаемся к нему, чтобы определить, // что загрузка всех шрифтов завершена. d.fonts.ready.then(function(fontFaceSet) { try { window.performance.mark("FontsLoaded"); } catch(ex) { exceptionHandling(ex); } }).catch(exceptionHandling); } catch(ex) { exceptionHandling(ex); } } }(this, this.document)); |
После того, как мы добавим этот код на страницу, мы можем найти элементы UserTiming в консоли разработчика:
Великолепно! А теперь самое интересное: Собираем данные!
Запуск UserTiming
Используя Boomerang, мы можем собрать эти данные с помощью плагина UserTiming. Для этого нам понадобятся следующие 2 элемента в файле plugins.json во время сборки Boomerang для установки:
1 2 3 4 5 6 7 8 9 10 |
{ "plugins": [ ... // UserTiming Compression "node_modules/usertiming-compression/src/usertiming-compression.js", // UserTiming Plugin "plugins/usertiming.js", ... ] } |
После того, как мы создали Boomerang с дополнительными плагинами, можно добавить на сайт сниппет boomerang и инициализировать Boomerang, после того, как он был загружен на странице с включенным Плагином UserTiming:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
(function() { function hookBoomerang() { if (window.BOOMR && BOOMR.version) { if (BOOMR.plugins && BOOMR.plugins.UserTiming) { BOOMR.init({ beacon_url: "/beacons", UserTiming: { enabled: true } }); } return true; } } if (!hookBoomerang()) { if (document.addEventListener) { document.addEventListener("onBoomerangLoaded", hookBoomerang); } else if (document.attachEvent) { document.attachEvent("onpropertychange", function(e) { e = e || window.event; if (e && e.propertyName === "onBoomerangLoaded") { hookBoomerang(); } }); } } }()); |
Теперь, когда мы готовы, можно использовать отладочную версию Boomerang и проверить консольный журнал логов, чтобы убедиться, что элементы UserTiming сжаты и отправлены.
Результаты
В консоли мы можем видеть, как Boomerang пересылает данные обратно на наш сервер:
1 2 3 4 5 6 7 8 9 10 11 12 |
boomerang: [debug] Ready to send beacon: ... t_done=2546 t_other=boomerang|2,boomr_fb|2443,boomr_ld|1165,boomr_lat|1278 ... restiming={"http":{"://www.andreas-marschke.name/":{...}}} u=//web.andreas-marschke.name/ v=1.0.1514544714 ... pid=svcbw6yv ... usertiming=0Bungee_normal_400_normal~108.~FontAwesome_normal_normal_normal~1vc.~FontsLoaded~1vd |
Элементы usertiming=… – очень важны, так как они содержат нужные нам данные. Теперь вы можете использовать механизмы распаковки библиотеки UserTimingCompression c npm
Используя заданный в пакете файл cmd.js, мы можем вставить приведенную выше запись:
1 |
0Bungee_normal_400_normal~108.~FontAwesome_normal_normal_normal~1vc.~FontsLoaded~1vd |
в файл типа compressed.txt и распаковать элементы:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
$> node cmd.js decompress compressed.txt | jq . [ { "name": "Bungee_normal_400_normal", "startTime": 1304, "duration": 0, "entryType": "mark" }, { "name": "Bungee_normal_400_normal", "startTime": 1304, "duration": 0, "entryType": "mark" }, { "name": "FontAwesome_normal_normal_normal", "startTime": 2424, "duration": 0, "entryType": "mark" }, { "name": "FontAwesome_normal_normal_normal", "startTime": 2424, "duration": 0, "entryType": "mark" }, { "name": "FontsLoaded", "startTime": 2425, "duration": 0, "entryType": "mark" } ] |
Как видите, для каждого из FontFaces указывается временя отображения (здесь в startTime) в миллисекундах.
Вот и все! Я надеюсь, что эта информация поможет вам оптимизировать использование веб-шрифтов и предоставить пользователями быстро загружающиеся страницы!
Дополнительно
Чтобы продемонстрировать вам доступность document.fonts, используемых на этой странице, ниже приводится таблица оценок для WebFonts:
Автор: Andreas Marschke
Источник: //www.andreas-marschke.name/
Редакция: Команда webformyself.