It became interesting how the code of the metrics counter works, but in JavaScript I am not very strong, I got to know him literally at the top.

(function(d, w, c) { (w[c] = w[c] || []).push(function() { try { w.yaCounterCOUNTER_ID = new Ya.Metrika({ id: COUNTER_ID, clickmap: true, trackLinks: true, accurateTrackBounce: true, webvisor: true }); } catch (e) {} }); var n = d.getElementsByTagName("script")[0], s = d.createElement("script"), f = function() { n.parentNode.insertBefore(s, n); }; s.type = "text/javascript"; s.async = true; s.src = "https://mc.yandex.ru/metrika/watch.js"; if (w.opera == "[object Opera]") { d.addEventListener("DOMContentLoaded", f, false); } else { f(); } })(document, window, "yandex_metrika_callbacks"); 

The construction at the very beginning of the function is not very clear. How will the new Ya.Metrika object be created if it is not actually in the code, and the watch.js script watch.js loaded in the code later?

And how does the watch.js script itself watch.js ? After all, if you look at the code of the page with the counter installed, the script tag with the parameters and the path to watch.js will not be visible in the page code.

Thanks in advance for the explanation!

    2 answers 2

    Great question! Let's go in order:

    1. Declaration and call of the main function

     (function(d, w, c) { ... })(document, window, "yandex_metrika_callbacks"); 

    Here you declare a certain function, and immediately after the declaration, you call it with the document , window parameters and the Yandex.Metrica string key. These parameters are used inside the function.

    2. Saving Metric Constructor

     w[c] = w[c] || [] 

    w is your browser window. In it, you can store functions or data, and they will be available globally in other scripts. In fact, here you are accessing w["yandex_metrika_callbacks"] , and there either will already have some values ​​(for example, from other Yandex.Metrica counters), or an empty array declared by you.

     .push(function() { ... ); 

    And then you add an element to this array (already existing or just created) - a function that tries to create a metric counter object.

     w.yaCounterCOUNTER_ID = new Ya.Metrika({ .. }); 

    Create the object again at the w window so that it is available in any other scripts.

    3. Asynchronous script load metrics

     n = d.getElementsByTagName("script")[0] 

    Here you find the first <script> tag on your site. The metric needs it here with this command ..

     n.parentNode.insertBefore(s, n); 

    .. Insert a new script created by it before your existing one. Before or after - it does not matter, the main thing is to place the script on the page, and the metric does it in a guaranteed way.

    It would be possible to place the script at the end of <body> or <head> , but recently these tags in the layout are optional. But the <script> on your site will definitely be at least one - with the metric counter code.

     s = d.createElement("script") s.type = "text/javascript"; s.async = true; s.src = "https://mc.yandex.ru/metrika/watch.js"; 

    Here, the metric just creates that <script> , which it then inserts into the page, and after insertion, the script will begin to load asynchronously.

     f(); 

    This is where the f function is called, which inserts the <script> metrics into the DOM. Slightly above there is an exception, in case Opera browser is used:

     d.addEventListener("DOMContentLoaded", f, false); 

    Which in the same way will execute function f, but after full loading of DOM'a the browser.

    4. Run an asynchronously loaded script

    As a result, the watch.js script is loaded asynchronously, and in the window["yandex_metrika_callbacks"] you have stored constructor functions for Yandex.Metrics objects.

    When the watch.js script loads, it will simply call all these functions in a row, thus initializing all the Yandex.Metrica counters that you want to see on the site.

    • Great answer! :) And could you give a tip on information on how to store functions in the window object? Rummaged on learn.javascript.ru, but did not find the information. Found common words about the object and methods. - kover-samolet
    • four
      @ kover-samolet, here you need to think about why you need global functions? And how many such functions do you need? It is considered good practice to avoid global objects and functions whenever possible, and if they are stored, they are in the form of thick objects containing all the necessary functions for working with something concrete. For example, the CKEditor editor stores all its data and functions in window.CKEDITOR , and it is through it that you can work with the editor in your scripts. - Vitaliy Emelyantsev
    • thanks for the answer! I will think :) - kover-samolet
    • one
      <body> and <head> optional in layout . But they are guaranteed to be present in the DOM anyway, so document.getElementsByTagName("body")[0] always return something. - Dmitry Shevchenko

    The construction at the beginning does not create an Ya.Metrika object , as was rightly noted, at this stage it is not there yet. This construction only adds to the window array . yandex_metrika_callbacks function that should create this object. And this function itself is called in the watch.js script when the Ya.Metrika object has already been created.

    At the expense of adding the script watch.js : It is added dynamically before the first script tag on the page at the moment. If you watch the page code through the view page source , then naturally you will not see it there, you need to use the developer’s tool in the browser (to open it, you can click on the page with the right button and select the inspect element item).