2

I'm using this script

<script type="text/javascript">
function downloadJSAtOnload() {
    var element = document.createElement("script");
    element.src = "defer.js";
    document.body.appendChild(element);
}

if (window.addEventListener) {
    window.addEventListener("load", downloadJSAtOnload, false);
} else if (window.attachEvent) {
    window.attachEvent("onload", downloadJSAtOnload);
} else { window.onload = downloadJSAtOnload; }
</script>

where defer.js is my minified combined file of all my JS functions for the entire site.

this technique is meant to defer the load to prevent the annoying google pagespeed warning:

"Eliminate render-blocking JavaScript and CSS in above-the-fold content"

but now, all my calls for document.ready > function A are now messed up...

is there a fix for it?

gromiczek
  • 2,970
  • 5
  • 28
  • 49
Francesco
  • 24,839
  • 29
  • 105
  • 152
  • clever use of the script load event – Jaromanda X Nov 29 '16 at 00:26
  • You have to give us a little more. What errors are you getting? Did you try to load a single file instead? What kind of debugging have you already done? – Ruan Mendes Nov 29 '16 at 00:26
  • 1
    Why not just put the script tag(s) at the end of the page, before the closing

    tag? That should eliminate the warning and improve performance.

    – Paul Nov 29 '16 at 00:30
  • the problem is that the function i call inside document.ready fires before the main JS file is loded... – Francesco Nov 29 '16 at 00:32
  • i don't think document.ready functions will be executed if you load in this manner. refer http://stackoverflow.com/questions/5610321/execute-document-ready-after-ajax-post and see if you can implement it – raj Nov 29 '16 at 07:23

2 Answers2

0

Ok,

So I can't say this is best practice but it seems pretty legit:

If you haven't played with Web Workers, I highly suggest at least taking a peek at the API.

<head>
  <script
      src="https://code.jquery.com/jquery-2.2.4.min.js"
      integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44="
      crossorigin="anonymous">
  </script>
  <title>Time for Web Workers!</title>
</head>
<body id="body">
  <script type="text/javascript">
      var worker = new Worker("js.js");
      worker.addEventListener("message",
          function (evt) {
            var script = document.createElement("script");
            script.innerHTML = evt.data;
            document.getElementById('body').appendChild(script);
          },false);
      worker.postMessage(1);    
  </script>

Web Workers breaks the limit of single threading when using javascript. The big setback with workers are that they cannot access the dom. The most that they can do is compute and pass data via messages.

Ah, but messages!

This is where it gets a bit messy, but stick with me.

var worker = new Worker("js.js");
// any data can be used as arg, but needed to trigger 'messages' listener
worker.postMessage(1); 

I first tried to send the postMessage() function to create a new Worker using a local js file. This works, but it causes the jQuery to remain undefined as the script is not availble to the thread. Separate threads, separate resources >_<

To get around this, we need the Worker to send the code back to the main thread to be executed under the dom's jQuery script. We can do this by setting our local js file to listen for the message event and return it's code base, as a string.

This can be done by using a dummy to import your minified local file and parse as a string, or by simply creating a string from your minified script and using it like so:

addEventListener("message",
    function (evt) {
      var script = 
          "$(document).ready(
             function() {
               var thisThing = 'blah';alert(thisThing);
             })";
            postMessage(script);
          }, false);

Back at the main thread, we set an event listener to listen for messages as well. In this function, we need to create a new <script> element and insert the stringified codebase into it before finally appending it to the body.

worker.addEventListener("message",
    function (evt) {
      var script = document.createElement("script");
      script.innerHTML = evt.data;
      document.getElementById('body').appendChild(script);
    },false);

Note

  1. I have not tested this with a large script
  2. I have only used a local development server to test this
  3. I have not tested any $(document).ready()-heavy code in the local script, so I do not know if this will even fix your issue..
  4. I had fun doing this :P
vulpcod3z
  • 194
  • 1
  • 12
-2

what about putting your javascript code at the very bottom of the page? that way it will not block any render process.

the code will not be executed because the ready even has been already called, so you should wrap all your code in anonymous functions so it will be executed immediately.

(function(){
 //do stuff here
})();
Oksid
  • 60
  • 3
  • `so you should wrap all your code in anonymous functions so it will be executed immediately` - that doesn't make sense, wrapping code in a IIFE does not change when it is executed – Jaromanda X Nov 29 '16 at 00:37
  • sorry but what do you mean by "does not change when it is executed"?, may be i misunderstood the issue. As i see it his issue is that the code that is loaded after the doc ready is not executed because it waits for the doc ready event which has been already called, so he should be fine to execute the code right after it loads in to the browser, right? – Oksid Nov 29 '16 at 00:46
  • you say you should wrap all code in an IIFE so it is executed immediately ... wrapping code in an IIFE does not change when code is run, if code runs immediately inside an IIFE, the same code runs immediately outside the IIFE - I can't make that statement any simpler - I am not referring to the question at all, just your incorrect statement about how an IIFE changes code execution - it doesn't – Jaromanda X Nov 29 '16 at 00:48
  • Ok i know what you mean now. My idea was leave out the document ready event completely – Oksid Nov 29 '16 at 00:53