Как сделать в яндекс метрике асинхронный код?

Всем привет! Подскажите как сделать в Яндекс метрике асинхронный код? В старых версиях раньше был чек бокс с выбором ставить с async или нет. В актуальной версии такого выбора нет ( Он как бы есть, но поставив код старой версии и там уже выбрать асинхронный код ), но хотелось бы актуальную версию. Либо async встроен в код в новой версии по умолчанию? Код счетчика актуальной версии Яндекс Метрики Почему везде рекомендуют код метрики устанавливать в конце тега body? Аргументируя это, якобы так уменьшается точность, но не страдает скорость загрузки). Но для меня не понятно, если код асинхронный, какая разница, где его устанавливать, ведь можно сделать по мануалу закинуть в header и радоваться более точным показателям и скорость как я писал за счет асинхронного кода не пострадает. Так в чем прикол?) Александр, может, Вы подскажите?

Комментарии: 11

Антон
Антон
Александр, а не могли бы вы уточнить еще 3 момента? У примеру если я закину скрипт Яндекс метрики в общий внешний файл со своими скриптами, чтобы все это быстрее грузилось, будет ли работать async у метрики? Учитывая что сам общий скрипт не асинхронный? Пример ниже ( если закинуть в "/js/script.js")???
</footer>
 <script src="/js/script.js"></script>
</body>
 
2) Стоит ли делать такой вариант, что метрика будет грузиться только после полной загрузки страницы? Это обеспечивает хорошие показатели в pagespeed. Проверено, но счетчик светится красным.
<script type="text/javascript" >
	  window.onReadyState = (e, t) => {
  const a = ["loading", "interactive", "complete"],
    o = a.slice(a.indexOf(e)),
    n = () => o.includes(document.readyState);
  n() ? t() : document.addEventListener("readystatechange", (() => n() && t()))
}
window.onReadyState("complete",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(000000, "init", {
        clickmap:true,
        trackLinks:true,
        accurateTrackBounce:true,
        webvisor:true
   });
    
})
      </script> 
3) Подскажите на моем примере: на 1 фотографии я закинул метрику в header (встроенный сценарий) на сколько я понял тут код метрики начинается грузиться параллельно всей странице и мы получаем такие показатели ->
<img
src=«https://itchief.ru/assets/uploadify/b/8/c/b8cba7392ca28f1f1f0bb75dadaa8278s.jpg» class=«fancybox thumbnail center»>


В этом примере я закинул метрику в общий внешний файл со своими скриптами, как писал выше в 1 пункте. Не знаю будет ли работать тогда асинхрон метрики. Но по логике вещей я понял принцип работы таким образом, что сначала грузится все стили и тд в общем страница а только потом все скрипты разом!? Показатели ниже ->
</footer>
 <script src="/js/script.js"></script>
</body>
 
<img
src=«https://itchief.ru/assets/uploadify/2/4/4/2447f39bf35cd6e6ead7a6a0af16d4d5s.jpg» class=«fancybox thumbnail center»>


В последнем примере просто закинул к закрывающему тегу body (встроенный сценарий) тут как я понял будет все тоже самое как в варианте выше, как если бы я его закинул в общей файл со скриптами? Либо же тут лучше? т.к будет работать асинхрон? Показатели ниже ->
<img
src=«https://itchief.ru/assets/uploadify/5/8/7/58720dea73e8a8d03c8aaf26fa0a11e0s.jpg» class=«fancybox thumbnail center»>

И среди всего этого не могу понять какой же вариант предпочтительней в моем случае… Буду Вам при много благодарен если дадите подсказку какой же вариант лучше выбрать)
Александр Мальцев
Александр Мальцев
Если вы вставите код Яндекс Метрики в общий внешний файл, то он всё равно будет загружен асинхронно. Код счетчика же очень простой. Он создаёт элемент script. Добавляет к нему свойство asynс со значением 1 и src со значением «https://mc.yandex.ru/metrika/tag.js». Далее находит самый первый элемент script на странице и подключает только что созданный элемент script перед ним. После этого браузер загружает скрипт Яндекс Метрики асинхронно (т.к. он имеет свойство async равное true) и после загрузки выполняет.

Поместить код Яндекс метрики в свой внешний скрипт или расположить его непосредственно на странице после подключения этого внешнего скрипта – это почти одно и тоже.

Почему вы свой внешний скрипт не загружаете в фоне? Сейчас уже никто не помещает скрипты в конец страницы. Лучше поместите свой внешний скрипт в head и добавьте к нему атрибут defer. В этом случае он будет грузиться в фоне и как только DOM дерево будет готово, то сразу выполнится. Вот это действительно может увеличить быстродействие, т.к. пользователь с ней сможет взаимодействовать намного раньше.

Если вы хотите выполнить код после того, как DOM будет готов, то используйте следующую конструкцию:
document.addEventListener('DOMContentLoaded', function () {
  // …
});
Статус счетчика может показываться красным если от него не было получено отклика (превышено время ожидания). Это может случиться, если страница очень долго загружается, а он подключен после полной её загрузки.

Для проверки лучше проводить несколько тестов, а потом вычислять среднее значение, которые затем уже сравнивать. У вас все результаты в пределах погрешности ±5%.

Какой вариант выбрать вы должны сами. У каждого варианта имеется свои плюсы и минусы. Кто-то одни плюсы и недостатки считает более весомыми, и предлагает делать так, кто-то считает наоборот и делает по-другому. И тот и другой может привести аргументы и отстаивать свой вариант.

Лично я в данный момент предпочитаю подключать все скрипты в head, тем которым нужен DOM с атрибутом defer, кому не нужен – async.
Антон
Антон
Александр, в очередной раз Вас Благодарю!!! На вопрос --> «Почему вы свой внешний скрипт не загружаете в фоне? Сейчас уже никто не помещает скрипты в конец страницы.» — Я правда не знал что так делают (скорее всего прочитал устаревшую информацию). Но сейчас все переделаю по вашему совету и закину в head! Во избежании с моей стороны лишних недопониманий, могли бы взглянуть на правки правильны ли они?) codepen.io/man129/pen/jOVQbVE
Яндекс рекомендует размещать его внутри тега body, но где именно внутри я так понял без разницы?
<noscript><div><img src="https://mc.yandex.ru/watch/73378066" style="position:absolute; left:-9999px;" alt="" /></div></noscript>
<!-- /Yandex.Metrika counter --> 
Напомню скрипт был в конце тега body->
</footer>
 <script src="/js/script.js"></script>
</body>
<code>
Еще раз Спасибо!
Антон
Антон
Еще 1 момент, я так понимаю из моего примера мне лучше использовать атрибут async (вместо defer)? Я тоже сторонник того, что пускай лучше браузер начнёт его загрузку cкрипта в фоне, не останавливая основной поток! =)
Александр Мальцев
Александр Мальцев
Пожалуйста! Да, так.
noscript разместили правильно сразу после открывающего тега body. Он нужен для того, чтобы получить данные о просмотре, когда браузер не поддерживает работу со скриптами или их поддержка отключена пользователем.
Скрипты с defer выполняются, когда DOM будет готов, но перед событием DOMContentLoaded. Если вы хотите выполнить скрипт метрики сразу, как только он будет готов, то можно так:
  ...
  <script defer src="/js/script.js"></script>
  <script>
    (function(m,e,t,r,i,k,a){ ... });
  </script>
  </head>
  ...
Александр Мальцев
Александр Мальцев
defer и async — имеют разное назначение. Если вам нужно загрузить скрипт асинхронно, но он нужен для выполнения действий с элементами на странице, то тогда лучше использовать defer. Т.к. он даже если загрузиться раньше будет выполнен только после того, как DOM страницы будет готов, но до события DOMContentLoaded. Если нужно загрузить скрипт асинхронно и выполнить его как можно скорее даже когда ещё DOM страницы может быть не построено, то async.
Антон
Антон
Понятно. 1 момент.А если сделать так как вы сказали ->
...
  <script defer src="/js/script.js"></script>
  <script>
    (function(m,e,t,r,i,k,a){ ... });  <- <b>тут оставлять все без изменений и просто copy-paste. Или что то добавить где ...?)</b>
  </script>
  </head>
...
Нужно ли будет из кода метрики который я закинул в внешний скрипт убирать что то, или оставить без изменения?
(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(0000000, "init", {
        clickmap:true,
        trackLinks:true,
        accurateTrackBounce:true,
        webvisor:true
   });
Александр Мальцев
Александр Мальцев
Конечно нужно оставить только в одном месте. Оттуда вырезать сюда вставить:
...
<script defer src="/js/script.js"></script>
<script>(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(********, "init", { clickmap:true, trackLinks:true, accurateTrackBounce:true, webvisor:true});</script>
</head>
...
Антон
Антон
Дошло), огромное спасибо!!!
Антон
Антон
Cпасибо!
Александр Мальцев
Александр Мальцев
Привет!

Новый код метрики по умолчанию является асинхронным. В нём это выполнено посредством установки свойству async значения 1 (true):
Код счетчика Яндекс метрики

1. Скрипт, который нужно загрузить асинхронно желательно поместить на страницу как можно выше (в head). Т.к. чем выше вы его поместите, тем быстрее браузер начнёт его загрузку (в фоне, параллельно) при этом не останавливая загрузку основного потока. В этом случае он загрузится и выполнится настолько быстро насколько это возможно.

2. Если поместить скрипт Яндекс метрики перед закрывающим тегом body, то сначала будет загружен весь основной поток (код, расположенный до него), и только после этого он. Он также будет загружаться в фоне, и после загрузки будет выполнен.

Мне больше нравится первый вариант, т.к. в скорости разницы не заметил, а показатели получаются более точные.

Для эксперимента обычно беру среднюю по загрузке страницу на сайте, оставляю на ней из внешних скриптов только Яндекс метрику, чтобы остальные внешние зависимости не влияли на результат и провожу тесты в Lighthouse.

Результат, когда Яндекс метрика подключена в head:
Группа показателей из категории Performance в Lighthouse, когда Яндекс метрика подключена в head

Результат, когда Яндекс метрика подключена перед закрывающим тегом body:
Группа показателей из категории Performance в Lighthouse, когда Яндекс метрика подключена перед закрывающим тегом body

Вывожу средние цифры по результатам нескольких текстов и затем их сравниваю.