Jump to content
iwato

Matomo: async, defer, and insertBefore()

Recommended Posts

Please find below the Javascript  insertion <script> tag that Matomo uses to track user behavior on a webpage.

<!-- Matomo -->
<script type="text/javascript">
    var _paq = _paq || [];
    _paq.push(['trackPageView']);
    _paq.push(['enableLinkTracking']);
    (function() {
        var u="//{$PIWIK_URL}/";
        _paq.push(['setTrackerUrl', u+'piwik.php']);
        _paq.push(['setSiteId', {$IDSITE}]);
        var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
        g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
    })();
</script>
<!-- End Matomo Code -->

I would like to clarify the meaning of the  final line of the above function -- namely,

g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);

QUESTION ONE:  Can the script attributes async and defer work indepedently of each another?  What is the purpose of each and does their role change when they are imlpemented together?

QUESTION TWO: Given the statement

s=d.getElementsByTagName('script')[0];

does the statement

s.parentNode.insertBefore(g,s);

read:  "Find the parent node of s and prepend g before s where s is the first node of all script nodes within the document including the  node containing this function"?

Share this post


Link to post
Share on other sites

The use of both async and defer is often done because old versions of Internet Explorer only understood the defer attribute. They're not mutually exclusive, async tells the browser to continue loading the rest of the page while the script is being downloaded. The defer attribute works the same, but deferred scripts are executed in the same order as they are in the DOM rather than executing each one the moment they finished downloading. The async and defer properties are explained in detail on this page: https://developer.mozilla.org/en-US/docs/Web/API/HTMLScriptElement

In short, x.parentNode.insertBefore(y, x) means to put y right before x in the document. It doesn't matter what or where x or y are as long as they're both DOM nodes. The insertBefore method works like appendChild(), but instead of putting it at the end of the children, it specifies one of the existing children of the node before which the new element should be inserted. W3Schools has a page explaining the insertBefore() method here: https://www.w3schools.com/jsref/met_node_insertbefore.asp

  • Like 1

Share this post


Link to post
Share on other sites

OK.  I have read through the MDN reference that you provided regarding the async and defer attributes.  Comparing this reference against your statement and my own reflection it appears that Javascript and HTML are treated separately by a browser.  This said, if no special action is taken Javascript will always be executed in the moment that it is read along with the other HTML tags in the document.

Further, if I have understood correctly, there are three ways to introduce Javascript into a webpage:  one,  it is executed in the order that it is read along with other HTML tags; two, although read in the order in which it appears amont other HTML tags it need not need be executed at the time it is read; and three, although read in the order in which it appears among other HTML tags, it is not executed until all of the HTML tags have been loaded, and when read, it is read in the order in which it was introduced among the other HTML tags.

In other words,

1) Javascript is synchronous when it is executed in the order that it appears along with the other HTML tags.

2) Javascript is asynchronous when the browser is not compelled to execute in the order that it appears among the other HTML tags

3) When the defer attribute is indicated and is assigned the value true,  the corresponding script is treated as if it were contained in a jQuery ready() method and not executed until all other HTML tags have been read.

QUESTION:  Is the above a proper understanding of the relationship between HTML, Javascript, and browser behavior?

Roddy

 

Share this post


Link to post
Share on other sites

It's not correct. Asynchronous is not about the order of execution, that is merely a side effect, but about whether or not the browser should halt loading the page when it comes across a script.

HTML just tells the browser what scripts to load and how to load them.

As for methods of loading Javascript, there are just two: synchronous and asynchronous.

When a script is synchronous, the page stops loading at the point where the <script> tag ended, waits for the entire script to download, then runs the Javascript from the file, then continues loading the rest of the HTML. This really slows down the page from loading which is why it is recommended to have script tags at the bottom of the document or to load them asynchronously. If you load scripts synchronously in the <head> section then the page will be blank until the scripts are done downloading.

When a script is loaded asynchronously, the page begins downloading the scripts but continues parsing the rest of the HTML on the page, waiting until the script has finished downloading before running it. The problem with this is that you cannot predict the order in which scripts will run: whichever script downloads the fastest runs first.

The defer attribute tells the browser to remember the order in which scripts were in the document, but this behavior is only predictable if all script tags have the defer attribute and not just some of them. Most of the time, the defer attribute is not used for that purpose and instead is just used to be backwards compatible with old versions of Internet Explorer because it does not support the async attribute.

  • Thanks 1

Share this post


Link to post
Share on other sites

Whether it is true or not, I have understood well what you explained.

Under the assumption that what you have stated is true, could it not then be said that the jQuery ready( ) function behaves as if each line of script contained within the function were assigned its own script tag and defer attribute?

Roddy

 

Share this post


Link to post
Share on other sites

For the purpose of discussion, let's leave out jQuery.  jQuery is just a wrapper over regular Javascript.  Instead of talking about jQuery's ready function, talk about the DOM document load event.  But, you can do a little bit of testing to answer your question.  Include whatever scripts you want on a test page using whatever methods you want, and have each of them use console.log to send a message to the browser's developer console.  When you load the page, you'll be able to see the order in which they execute.  If you refresh the page you might get different results based on the options you used.

Share this post


Link to post
Share on other sites

JSG:  But, you have set aside the very thing that I was trying to understand -- the jQuery ready( ) function.

If I have understood this function correctly, it allows the Javascript contained within the function to be read as the rest of the page is being downloaded, but does not permit what is read to be executed until the rest of the page has been completed.  My question, then: does the jQuery ready() function also insure that the Javascript thus read and loaded execute in the order that it is entered into the ready function?

Roddy

Share this post


Link to post
Share on other sites

They may be read and executed, but a executed code may not completely finish before other code is executed. Unless you specifically create the code to run after the previous is completed.

The jQuery ready( ) function acts as a onload event itself and is mainly used for presetting, manipulation of elements, and adding events to specific elements after the pages html has been fully rendered.

Share this post


Link to post
Share on other sites

If I have understood this function correctly, it allows the Javascript contained within the function to be read as the rest of the page is being downloaded, but does not permit what is read to be executed until the rest of the page has been completed.  My question, then: does the jQuery ready() function also insure that the Javascript thus read and loaded execute in the order that it is entered into the ready function?

It's not magic, like all the rest of jQuery it's just a wrapper for existing vanilla Javascript.  jQuery does not add any functionality, all it does it make certain things easier to use.  The only scripting language all modern browsers understand is Javascript, so anything like jQuery is ultimately written in and uses vanilla Javascript.  For the ready function, it's just a wrapper for the document.load event.  More specifically, and recently, it probably just runs document.addEventListener if that's available.  In terms of what it does, you just declare and pass a function to it which will get executed when the event happens.  It's not about "permitting" things to run, things happen in a well-defined order, and as far as I know the event handlers do get executed in the order in which they're added but I believe they also get executed asynchronously.  That's why I said to leave jQuery out of the discussion - if you want to understand what it does, you only need to understand the underlying Javascript concepts on which jQuery is built.  If you understand that then you can review the jQuery source code to see how jQuery specifically uses the built-in functionality.

The source code for that is here:

https://github.com/jquery/jquery/blob/master/src/core/ready.js

Lines 71 through 84 set up the actual DOM event to execute jQuery's own event handler, which is the completed function, which calls the internal ready function, which runs each handler on line 54.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×