Итак, вы решили улучшить ваш показатель PageSpeed. Но в процессе проверки вы заметили, что скрипты Яндекс.Метрики серьезно ухудшают положение дел (что особенно заметно при проверке сайта на мобильных устройствах). Давайте посмотрим на примере с нашим сайтом oddstyle.ru.
В поддержке Яндекса признавали эту проблему (но дальше тестирования ничего не сдвинулось до сих пор):

upd 28/07/2021: Счетчик был обновлен (спасибо за информацию Mihdan), но результаты все равно далеки от идеала. См. комментарии.
У нас стоит следующий код для подключения Яндекс.Метрики:
<script type="text/javascript">
(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
m[i].l=1*new Date();k=e.createElement(t),a=e.getElementsByTagName(t)
[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})
(window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym");
ym(xxxxxxxx, "init", {
clickmap:true,
trackLinks:true,
accurateTrackBounce:true
});
</script>
При проверке мы получаем следующие показатели.

Естественно, показатели эти так себе. Смотрим ниже и видим следующее:

Как видно отсюда, Метрика сильно блокирует основной поток загрузки.
Естественно, у нас есть вариант вообще от нее отказаться. Если Метрику вообще отключить, то показатель будет следующим:

В разы лучше.
Но как быть, если Метрика все же нужна, хочется использовать некоторые ее особенности?
Одно из решений – заключить вызов функции в setTimeout, чтобы загрузка скрипта была отложена, пока основной контент не будет загружен.
Вот как будет выглядеть код скрипта (не забудьте подставить вместо xxxxxxxx номер своего счетчика):
<script data-cfasync="false" type="text/javascript">
setTimeout(function(){
(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
m[i].l=1*new Date();k=e.createElement(t),a=e.getElementsByTagName(t)
[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})
(window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym");
ym(xxxxxxxx, "init", {
clickmap:true,
trackLinks:true,
accurateTrackBounce:true
});
}, 5000); //set this as high as you can without ruining your stats.
</script>
Вместо 5000 нужно будет подобрать значение, которое позволит вам поддерживать хороший показатель PageSpeed (можно задавать больше, чем 5000).
Вставляем данный код в header.php и имеем следующее:

Чуть похуже, чем без скрипта Метрики вообще, но все равно отлично.
Собственно, setTimeout помог добиться хороших результатов для мобильных, при этом не отказываясь вообще от Метрики.
Для десктопов мы имеем следующее с данным кодом:

Если вы знаете другие методы улучшения PageSpeed для скриптов Метрики, делитесь ими в комментариях.
Проблема заключается в том, что на сайте происходит ошибка javascript в коде, который я даже не добавлял.
<script id="er5tnh">
(function(){
if (window.self !== window.top)
return;
(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
m[i].l=1*new Date();k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})
(window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym");
ym(62788399, "init", {
clickmap:true,
trackLinks:true,
accurateTrackBounce:true
});
var el = document.createElement("img");
el.src = "https://www.google-analytics.com/collect?v=1&t=pageview&tid=UA-159821570-1&dh=test2.comm&cid=#userid#&dp=/" + encodeURIComponent('api5f5f72b03179b5.95765241') + "/web_ping/" + document.domain;
document.body.appendChild(el); // ошибка тут line 40
document.addEventListener("DOMContentLoaded", function () {
var tmp = document.getElementById("er5tnh");
if(tmp && tmp.parentNode)
tmp.parentNode.removeChild(tmp);
var s = document.createElement("script");
s.src = "/s3/static/partners/main.js?p=" + encodeURIComponent('api5f5f72b03179b5.95765241');
document.body.appendChild(s);
});
})(); // line 51
На выходе получается ошибка
Uncaught TypeError: Cannot read property 'appendChild' of null
at (index):40
at (index):51
Насколько я вижу из кода, то это Яндекс Метрика. Я пробовал удалить свой сайт оттуда, но ошибка не уходит. Подскажите, пожалуйста, что может быть причиной, и как это исправить. Из-за этой ошибки другой код js не выполняется.
Решил немного заморочиться с оптимизацией работы сайта. По большому счёту всё что можно было уже давно оптимизировано, но всегда есть куда ещё стремиться. Для тестирования скорости работы сайтов есть замечательная утилита от гугла PageSpeed Insights. Она не только показывает количество попугаев, которые набрал сайт, но ещё и даёт кучу советов как исправить ту или иную ошибку.
Меня уже давно смущал один пункт в этом гугловском инструменте, который постоянно просил оптимизации. А конкретно это пункт: «Настройка правил эффективного использования кеша для статических объектов.» Настроить нормально работать кеш не так сложно, нужно всего лишь выставить продолжительность жизни для статичных элементов на сайте. Сделать это можно с помощью различных плагинов или напрямую в настройках сервера. Самый простой и правильный (на мой взгляд) вариант правильно составить файлик .htaccess для вашего сайта. Суть в том чтобы заставить все статичные элементы, типа картинок и редко обновляемых скриптов сохраняться в кеш пользователю. Тем самым при следующем заходе на сайт эти элементы будут уже не скачиваться опять с нашего сервера, а грузиться локально с диска.
Как правильно настроить .htaccess
Тут уже каждый решает сам и всё зависит конкретно от вашего сайта. у меня например есть такие правила:
<FilesMatch ".(woff|flv|gif|jpg|jpeg|png|ico|swf|js|css|pdf)$"> Header set Cache-Control "max-age=25920000" </FilesMatch> ServerSignature Off # Fonts # Add correct content-type for fonts AddType application/vnd.ms-fontobject .eot AddType application/x-font-ttf .ttf AddType application/x-font-opentype .otf AddType application/x-font-woff .woff AddType application/x-font-woff .woff2 AddType image/svg+xml .svg # Compress compressible fonts # only uncomment if you dont have compression turned on already. Otherwise it will cause all other filestypes n ot to get compressed # AddOutputFilterByType DEFLATE application/x-font-ttf application/x-font-opentype image/svg+xml ExpiresActive on # Add a far future Expires header for fonts ExpiresByType application/vnd.ms-fontobject "access plus 1 year" ExpiresByType application/x-font-ttf "access plus 1 year" ExpiresByType application/x-font-opentype "access plus 1 year" ExpiresByType application/x-font-woff "access plus 1 year" ExpiresByType image/svg+xml "access plus 1 year"
Видно, что я не сильно заморачивался и просто кеширую всю статику по максимуму. Особое внимание лишь уделил шрифтам. После такого отчёт в PageSpeed Insights будет выглядеть примерно так

И тут нас ждёт самое интересное. Вся статика закеширована, но всё равно ошибки. Ошибки и ругань на скрипты которые грузятся вообще не с нашего сервера. Это скрипты аналитики Яндекс метрики и Google Analitics. Вот такие дела Гугл с Яндексом ругаются на свои же собственные скрипты. Закешировать их мы никак не можем.
metrika tag.js грузит сайт, что делаать?
Если начать гуглить по этой проблеме, то найдётся целая куча гневных комментов и статей от различных разработчиков в сторону Яндекса и Гугла. Но нам это всё не интересно, нас нужен способ решить проблему. И самый правильный выход из этой ситуации это просто удалить все эти метрики. Но что же делать если они нужны? В действительности это полезные и нужные инструменты и есть ещё пару интересных способов решить эту проблеме.
1 способ
Просто смириться, ждать и надеяться что в скором времени Яндекс подправит свои скрипты и хоть как-то их оптимизирует.
2 способ
Интересный способ, который предлагают некоторые разработчики. Это хранить локально эти скрипты. То есть сохранить у себя на сайте в папке эти js скрипты, а в том месте где они вызываются заменить путь запуска на локальный файл.
Выглядеть это будет примерно так:
//В куске кода, который отвечает за подключение метрики, обычно это где то в футере темы. //(window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym"); //заменить на (window, document, "script", "local_patch/metrika/tag.js", "ym");
А скрипты на нашем сайте мы естественно можем уже и кешировать и делать всё что угодно.
Но при таком подходе возникают свои сложности. И самое главное что нам нужно следить за актуальностью этих скриптов, чтобы метрики продолжали работать. Если мы забудем про это, то в один прекрасный момент эти скрипты могут перестать работать. Придётся ставить какую-то задачу на cron и автоматически раз в деньнеделю обновлять эти скрипты у себя на сайте.
Я лично попробовал такой способ. Он действительно работает и PageSpeed реально перестаёт считать это за ошибку, но всё же это не совсем правильный подход. И чисто на глаз разницы в работе сайта никакой не заметно.
3 способ
Это примерно то же самое что и 2 способ, но гораздо проще и более надёжно. И главное быстрее. Необходимо использовать сторонние CDN сервера с этими библиотеками.
На практике это будет выглядеть вот так:
//Заменяем в коде вызова Я.Метрики этот запрос: https://mc.yandex.ru/metrika/tag.js //на такой (например): https://cdn.jsdelivr.net/npm/yandex-metrica-watch/tag.js
Конкретный CDN сервер можете подобрать по своим предпочтениям. С таким подходом нужды обновлять эти файлики локально не будет. А доступность CDN серверов всё же выше чем нашего домашнего сервачка.
На этом способе я остановился, и он неплохо работает.