17

In my website I have many inline javascript snippets. Most of them require jquery and similar stuff.

But I would like to defer jquery load to after the page was rendered. And that means, that my inline javascript would execute, before jquery was loaded. Is there anything I can do about it? I am looking for easy to implement solutions (I also cannot move my inline javascript since it is automatically generated while page is being prepared for the user).

ojek
  • 8,047
  • 16
  • 65
  • 106
  • Can you give an example of what you mean by inline? Is is actually inside the HTML elements? Or do you mean each in it's own ` – Lix Nov 24 '13 at 20:29
  • Also, it sounds like you have control of the javascript (because you have a conflict with jquery execution order). I suspect this can be solved another way... – Dane O'Connor Nov 24 '13 at 20:30

2 Answers2

11

It would be much better if you could place your javascript at the end of the document. Sprinkling your source with small inline javascript snippets is a killer on page performance.

That said, you could create an array and push functions on this array. Then, at the end of your page, right after you load jquery, loop over the array and execute each function.

E.g.:

<html>
  ...
  <script>window.loadEvents = [];</script>
  ...
  <script>loadEvents.push(function() { alert("inline code here"); });</script>
  ...
  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
  <script>$.each(loadEvents, function(_,f) { f(); });</script>
</html>

However - as I said - it would be better to just push all the script elements into the bottom of the page, instead of switching back and forth between html and javascript. The rendering performance will be severely degraded, if you do this.

troelskn
  • 107,146
  • 23
  • 127
  • 148
8

You could simulate a defer by setting the type of the inline scripts to one that would not be processed by the browser like text/example, and the cloning those scripts at the end of the document replacing the type with text/javascript.

The code that processes all the text/examples is really simple:

window.addEventListener("load", function() {

    var arr = document.querySelectorAll("script[type='text/example']");
    for (var x = 0; x < arr.length; x++) {
        var cln = arr[x].cloneNode(true);
        cln.type = "text/javascript";
        document.querySelectorAll("body")[0].appendChild(cln);
    }

});

Or if you prefer to use jQuery (you'll have to add this script after including the jQuery file):

$(function() {
    $("script[type='text/example']").each(function() {
        $(this).clone().attr("type","text/javascript").appendTo("body"); 
    });
});

This code waits until the page has loaded, then selects all the scripts with type text/example, and copies them at the end of the body with a type of text/javascript so they are executed normally.

For example:

...
<script type="text/example">
    console.log("I am before the h1");
</script>

<h1>Page Title</h1>

<script type="text/javascript">
    console.log("I am after the h1");
</script>
...

Will result in these messages in the console:

I am after the h1

I am before the h1

You can see a running demo on this JSFiddle: http://jsfiddle.net/rqckwc79/


Pros of this solution:

  • It is a cross-browser solution.
  • The code is valid HTML/JavaScript.
  • It works in strict mode.

Cons of this solution:

  • You need to have control over the inline scripts to change the type.
  • As troelskn said, performance would be worse than moving all the code to the bottom (but I understand there are situations in which that is not possible).
  • It doesn't work on older IE versions (although the code could be modified to support them).
Alvaro Montoro
  • 23,383
  • 6
  • 47
  • 81
  • I know I'm _a bit_ late for this question, but I saw that [other](http://stackoverflow.com/questions/21013554/defer-loading-of-javascript-uncaught-referenceerror-is-not-defined) [users](http://stackoverflow.com/questions/27302242/how-to-use-defer-for-inline-javascript) asked related questions and were referred here. Just so they have another option that doesn't require changing header/footer to defer inline script – Alvaro Montoro Apr 16 '15 at 16:33
  • 1
    This is a very good solution for deferring JavaScript, especially in a Pagespeed-friendly way. Thanks. By older IE, I guess you mean less than version 8?! – BannerMan Aug 18 '15 at 14:15
  • Yes. This solution uses `querySelectorAll` that is only supported from version 8 of IE (and only partially for that particular one). I also have a version that will work also on IE 6 & 7, but it's more complex (and a bit _hacky_) – Alvaro Montoro Aug 18 '15 at 18:01
  • I figured. IE8 is my current baseline; it's nothing short of misery if you go any lower. – BannerMan Aug 18 '15 at 21:06