views:

68

answers:

2

We have a few places where we include inline <script> blocks which run code, wrapped by $(document).ready(). Several of these blocks use methods dependent on other external scripts. During normal page execution this technique works fine, but when the user navigates away from the page before it's completely loaded, the $(document).ready() event is triggered and IE is throwing "Object does not support this property or method" errors left and right.

Through some testing I've found out that the window.beforeunload event is triggered before any of the ready events, so I'd like to be able to prevent the ready events from being triggered at that point. Ideally I'd like to have a solution that generalizes so I don't have to modify all of the inline code.

If that's not possible would you suggest wrapping all of the inline code in try-catch blocks, determining if all the external scripts have been loaded before executing the inline code, etc?

+1  A: 

The inline scripts should not be peppered throughout like that if the plugins are loaded after the fact.

A better way, IMO, is to set up your pages like this:

<html>
    <head>
        <title></title>
    </head>
    <body>
        <div id="content">
        </div>
        <script src="jquery.js"></script>
        <script src="jquery.customerPlugins.js"></script>
        <script>
            $(function(){
               // all inline would go here!
            });
        </script>
        <script src="main.js"></script>
    </body>
</html>

But if that isn't an option you could (but probably shouldn't) (untested code below):

<html>
    <head>
        <title></title>
        <script src="jquery.js"></script>
        <script>
            var readyQueue = [];
        </script>
    </head>
    <body>
        <script>
            readyQueue.push(function(){
               $("body").append("<div />").customPlugin();
            });
        </script>
        <div id="content">
            <script>
                readyQueue.push(function(){
                   $("#content").customPlugin();
                });
            </script>
        </div>
        <script src="jquery.customPlugins.js"></script>
        <script>
            // do something like this...
            $(function(){
               var fn;
               while(fn = readyQueue.shift()){
                   fn();
               }
               // if you want to continue to use readyQueue in code 
               // below/after this you could do something like the following:
               readyQueue = {"push": function(fn){
                   fn();
               })};
               // this would execute immediately:
               readyQueue.push(function(){
                   alert('Hello');
               });
            });
        </script>
        <script src="main.js"></script>
    </body>
</html>

While you're at it, check out html5boilerplate.com.

David Murdoch
Definitely agree that it would be better to consolidate the inline JS. Unfortunately that's a bigger project than I have time for at the moment.
nleach
Try the second option. It is more proof-of-concept than actual code (its not tested). The [].push to push function trick is very similar to the methods most async scripts out there (google analytics is similar).
David Murdoch
+1  A: 

Ended up going with the following solution:

<script type="text/javascript">
 window.onbeforeunload = function(){
  $.readyList = null;
 }
</script>

It's a little hackier than I would have preferred, but it gets the job done.

nleach
useful hack. +1 for future use ;)
naugtur