0

Since I swapped from prototype to jquery i'm going through a lot of performance issues I never knew existed before.

but that's not the question. The question is about this function i'm using: (note we have a huuge web application) I'm using this function:

<!DOCTYPE html>
<html>
<head>
<link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1/themes/base/jquery-ui.css" rel="stylesheet" type="text/css" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>


<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-ui.min.js"></script>



<meta charset=utf-8 />
<title>JS Bin</title>
</head>
<body>
  <div title="jquery ui exists" style="width: 500px; height: 500px; background-color: lightblue"  >hover me</div>
  <script>
  var MyApp ={
        loadJsNow: function(libFilename){
                //the synchronous call ensures the library is in fact loaded before this
          //(which does not work for crossdomain requests, just for docu)
                //function returns:     

                $.ajax({
                        url: libFilename,
                        dataType: "script",                     
                        type: "GET",
                        async: false,
                        cache: true,
                        complete: function(data){
                           $("div").tooltip();
                        }

                });


            }
    }


       MyApp.loadJsNow("http://ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-ui.min.js");


  </script>



</body>
</html>

So this function is used to load js files if they are required for a certain element of the web page. Since we have so many pages with sometimes little on them, and sometimes loads on them, this approach seemed to make sense. BUT: Since this functions loads on demand, and not like standardly in the header, i'm not sure whether this creates a performance problem by itself. In FF 10 i get 200-600 ms see here

Have a look here at the different approach with the hardcoded values in header:

Hardcoded head js links i'm getting ~100-300 ms

drop all support for the on demand loading? do you get similar results?

EDIT i want to crossreference this question, because it seems relevant since jquery / firefox seems to not deal the caching of the on demand javascript loading correctly. Sometimes it works, then on the same page it does not work again.

Community
  • 1
  • 1
Toskan
  • 13,911
  • 14
  • 95
  • 185
  • 1
    There's usually little point in dynamically loading a script if you KNOW you're going to need it on the page. May as well load it right away with inline code and get it over with. – Blazemonger Nov 08 '12 at 14:31
  • 4
    Not specifiying the exact version from the Google CDN pretty much ensures that your sripts are'nt cached anyway, so start by defining the version and not just /1/ for the newest version to make sure they have an expiration date and are cached. Also try not to load the entire UI library if you don't need it. You can build it with just the methods you need from the jQuery UI site. – adeneo Nov 08 '12 at 14:34
  • 2
    Yep, and put stuff just above `

    ` rather than in your head. The CDN thing is massive though, not sure how many people realise that the freshest version link isn't cached.

    – Rich Bradshaw Nov 08 '12 at 14:34
  • @ŠimeVidas I think the ` – Blazemonger Nov 08 '12 at 14:37
  • 1
    @RichBradshaw - I really don't even understand why Google offers that approach, as it defeats the entire purpose of using the CDN, where the main advantage would be that users already have the script cached in the browser. They should label it with a huge warning "This method sucks as no caching will be enabled" ! – adeneo Nov 08 '12 at 14:39
  • Actually, I just checked via curl, and seems that actually they do have last-modified, but the Expires is set to 20 minutes. If you ask for say, jQuery 1.8.1 then Expires is set to 1 year. So, it's not quite no caching, but you should definitely pick a version and subversion. – Rich Bradshaw Nov 08 '12 at 15:29
  • @adeneo I use CDN because I had to to demonstrate it using jsbin. I was able to get cached libraries from my jsbin links, I could see it in firebug. And concerning the "try not to load everything" - did you open my testpage with hardcoded header? did you try it with cached libraries? did you get similar results of under ~100ms? just wondering, not wanting to be annoying. – Toskan Nov 08 '12 at 15:30

2 Answers2

1

Have you considered using requirejs instead? I'm not one for responding to a question and giving an answer not directly relevant to the question, but in this case it might really help you.

I modified your script to use requirejs and to still use async and to fire events when done. This will allow for multiple, async requests for multiple scripts but still only execute when all the scripts are ready.

http://requirejs.org/docs/api.html

http://jsbin.com/oxekod/9/edit

<!DOCTYPE html>
<html>
<head>
  <script type="text/javascript">var startDate = new Date();</script>

<link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1/themes/base/jquery-ui.css" rel="stylesheet" type="text/css" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
  <script src="http://requirejs.org/docs/release/2.1.1/comments/require.js"></script>
<!--
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-ui.min.js"></script>
-->


<meta charset=utf-8 />
<title>JS Bin</title>

    <!-- make sure this is declared in head -->
    <script>
  var MyApp ={
     queue: []
     , loadJsNow: function(strScript)
    { // add to the queue, but don't start loading just yet...
                MyApp.queue.push(strScript);
    }
  };
  </script>
</head>
<body>
  <div title="jquery ui exists" style="width: 500px; height: 500px; background-color: lightblue"  >hover me</div>

  <!-- throughout your app, add scripts as needed -->
  <script>
    MyApp.loadJsNow("http://ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-ui.min.js");
  </script>

  <script>
    $(function()
      {
        // when everything's ready, run your scripts through require.
        // after require loads ALL scripts, let jquery trigger a custom event called, say, 'scriptsloaded'
        require(MyApp.queue, function() { $(document).trigger('scriptsloaded'); });
      });
  </script>

  <script>
    $(document).on('scriptsloaded', function()
      {
        // anything that needs to wait for dynamic scripts should wait for the custom event to fire on document
        // once fired, all scripts are loaded, and do what you want.
        $('div').tooltip();

        var endDate = new Date();
        alert('diff: ' + (endDate.getTime() - startDate.getTime()));
      });
  </script>

</body>
</html>
Eli Gassert
  • 9,745
  • 3
  • 30
  • 39
  • +1 because I was unable to come up with that idea of triggering my own event when I loaded everything. BUT: with your approach I get roughly 300ms. With links in header I get < 100ms. Do you get similar results? Because if I can add everything statically to head, and just be lightning fast, why bother with dynamic loading which in the end of the day, is superslow? – Toskan Nov 08 '12 at 15:34
  • @Toskan I updated my script above to add "tming" events. To toggle between static and requirejs, I just uncomment the static script line and `//` js comment out the `MyApp.loadJsNow` line. For both I get roughly 300-400ms when clicking "Run with JS" over and over in jsbin. What results are you seeing? – Eli Gassert Nov 08 '12 at 19:18
0

As Eli Gassert suggested you can use a thirdparty dependency loader To do it on your own change your function to this

  loadJsNow: function(libFilename){

      var fileref=document.createElement('script');
      fileref.setAttribute("type","text/javascript");
      fileref.setAttribute("src", libFilename);
     }

This will load the file but it will not be in the DOM. If you want you can add them to the header add this into MyApp:

headElementRef: document.getElementsByTagName("head")[0],

and this into the method:

  this.headElementRef.appendChild(fileref);
Erv
  • 405
  • 2
  • 6