1

we have javascript code that injects elements into the DOM. Therefore it needs to wait until the DOM is in the required state.

We use the following for this:

document.onreadystatechange = function () {
    if (document.readyState === "interactive") {
        if (!tagsPlaced)
            placeTags();
    }
};

var DOMReady = function(a,b,c){b=document,c='addEventListener';b[c]?b[c]('DOMContentLoaded',a):window.attachEvent('onload',a);};
DOMReady(function () {
    if (!tagsPlaced)
        placeTags();
});

When there is a site with a slow or not loading script, it never fires these events..

The site is fully useable from the user perspective, and if we call "placeTags" manually it works as well.

One solution would be to call "placeTags" from the footer of the page. Unfortunately, we need to support loading the javascript anywhere on the page.

What can be done?

user2693017
  • 1,750
  • 6
  • 24
  • 50

1 Answers1

2

Use the defer attribute on the script tag for the code, and run your code immediately when your script is evaluated, rather than waiting. All even vaguely-modern browsers (including IE10 and IE11) support the defer attribute:

<script src="/path/to/your/script" defer></script>

If for some reason you can't do that (or can't rely on it being done), you can detect what it is that placeTags needs (whatever that is) and use a setTimeout loop until/unless that thing appears. For instance, if you needed to wait for a particular element to show up in the DOM, that might look like this:

(function boot(retries) {
    if (/*...condition your script needs is met...*/) {
        placeTags();
    } else {
        if (--retries <= 0) {
            // Give up, it's been at least a minute (100ms * 600 retries)
        } else {
            // Try again in 100ms
            setTimeout(boot, 100, retries);
        }
    }
})(600);
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • That's a good answer, thank you. Some of the processes in the script need to run as early as possible and don't need the DOM. Is there a way to defer contents of the script without the need to load another script which would add latency? – user2693017 May 22 '20 at 18:02
  • @user2693017 - No, I'm afraid a single script is either entirely deferred or entirely not deferred. If both the server and browser speak HTTP/2 (all vaguely-modern browsers do, including IE11), though, latency is a much smaller issue than it used to be thanks to pipelining, etc. – T.J. Crowder May 23 '20 at 08:28
  • @user2693017 - You might be tempted to use a small inline script. If you are, beware that `defer` doesn't work on inline scripts, only scripts with a `src`. However, if you're only targeting properly modern browsers, *modules* are deferred by default, including modules with inline script. So `type="module"` with inline content (on a modern browser) will be deferred. – T.J. Crowder May 23 '20 at 08:29