0

I had to manage an array of functions (with parameters), and execute them when onload event fires.

I know I could use jQuery's $(window).load(), but we all know that to reduce page loading time, every js script (jquery, jquery plugins, ...) must be inserted at page bottom, just before </body>.

Therefore the only js I'm loading in <head> is this:

var fn_chain = [];

function addFn2Load(fn) {
    if(typeof fn != 'function')return;
    fn_chain.push(fn);
}

function doLoad() {
    for(var i=0,iL=fn_chain.length;i<iL;i++) {
        fn_chain[i]();
    }   
}

if (window.addEventListener) {
    window.addEventListener("load", doLoad, false);
} else if (window.attachEvent) {
    window.attachEvent("onload", doLoad);
} else if (window.onLoad) {
    window.onload = doLoad;
}

Then I can push functions in my array from everywhere in the page, without the need of loading jQuery first. I just write

addFn2Load(function() {
    foo(arg1, arg2, argN);
    bar(arg1, arg2);
    $("#myElementId").myCoolPlugin(); // I can use $ even if jQuery is not loaded yet
});

My solution simply works... Could some javascript guru tell me if I'm doing it right? Is it improvable?

  • I am (more than) a little puzzled by this, especially the comment in "`$("#myElementId").myCoolPlugin(); // I can use $ even if jQuery is not loaded yet`". What are you actually trying to accomplish? – Gone Coding Mar 06 '14 at 15:09
  • "I can use $ even if jQuery is not loaded yet" No you cant' but as it seems to be called once window is loaded, then jQuery is already included – A. Wolff Mar 06 '14 at 15:09
  • @A.Wolff yes you're right. –  Mar 06 '14 at 15:12
  • @TrueBlueAussie I'm collecting functions and execute them when onload event fires without the need of loading jQuery first. Read A. Wolff 's answer. –  Mar 06 '14 at 15:14
  • If all of your javascript is at the end, you don't need the array of functions. Also, you're still using the window load event, which you likely don't need for 90% of your code. – Kevin B Mar 06 '14 at 15:14
  • @KevinB No, some js code is nested deep into the DOM. At the document's end there are jquery and some other jquery plugins. So I really need the array of functions. Is there a better way to accomplish that task? –  Mar 06 '14 at 15:19
  • Collect all of that javascript into a server-side variable and inserting it at the bottom using server-side script would be one option. I still suggest differentiating between code that needs to run on window load vs immediately. – Kevin B Mar 06 '14 at 15:20
  • No way man I'm not gonna use server-side scripting, but thanks for suggestion. Yes I'm already separating code that needs to run on window load vs immediately. –  Mar 06 '14 at 15:41
  • There is no reason to delay scripts to run from the bottom of the page when you're running them on window load, because the window is available everywhere. If you're adding script in the middle of the page to add to an array that gets executed at the end, you're missing the whole point of putting all scripts at the bottom. – Kevin B Mar 06 '14 at 16:53

2 Answers2

0

The window.load events fire AFTER the jQuery.ready event. See this other question. So the answer is no, you're not doing this quite right. The only reason you're able to use $ is becuase jQuery did already load.

As @Kevin B mentioned, if you have code that does not require for the document to be ready, you should separate those and run those directly (don't use window.onLoad or jQuery.ready).

<script>
    /* Do all your non jQuery stuff here, don't bind to any event handlers. */
</script>
<script src="http://code.jquery.com/jquery-1.11.0.min.js" />
<script>
    jQuery(document).ready(function($){
        /* do your jQuery stuff here */
    });
</script>
<script src="js/my_jq_plugins_minified.js" />

If you want a better way to execute callback functions with arbitrary arguments, I would use:

<script>
    function _trigger_callbacks(callbacks) {
        var i;
        for(i = 0; i < callbacks.length; i++) {
            callbacks[i][0].apply(this, callbacks[i][1]);
        }
    }

    // Prepare an array where each entry in this array is an array. For each array:
    //  - the first entry should be a function
    //  - the second entry should an array of arguments
    fxns = [
            [function(a){ alert("Do " + a);}, ["Apple"]],
            [function(a, b, c){ alert("Minus = " + (a - b - c));}, [1,2,3]],
    ];

    _trigger_callbacks(fxns);

</script>

For more on the Function.apply method, see this other question.

Community
  • 1
  • 1
MjrKusanagi
  • 1,284
  • 9
  • 19
  • Dude I do know load fires AFTER ready! Read @A.Wolff answer please. Your example is not right for my case because one thing I want to avoid is loading jQuery first. Have you read my post? –  Mar 06 '14 at 15:49
  • Yes I have, sorry for misunderstanding. I updated the answer accordingly. – MjrKusanagi Mar 06 '14 at 16:07
  • Actually I'm using anonymous functions, this way I do not need multidimensional arrays nor overloading due to `apply()` calls. Anyway I'm doing some benchmarking using your solution as well. –  Mar 06 '14 at 21:38
0

Doing this with javascript makes little to no sense. The purpose of including your external scripts at the bottom of the page is to allow the page to be generated before downloading the javascript which will result in a faster looking page load.

If you are including scripts in the middle of the page that add function calls to an array that gets executed at the bottom, that defeats the whole purpose of including the scripts at the end because those scripts will have to be downloaded before the rest of the page after said scripts are generated.

If you're pages are dynamically generated with a dynamic header and footer, it would be much easier and more efficient to do this work server-side. If they aren't being generated dynamically, then i don't understand why you are including scripts in the middle in the first place.

Kevin B
  • 92,700
  • 15
  • 158
  • 170
  • Ty again... That _faster looking_ effect is (along with other things) the target I want to reach. In fact, page now loads smooth. As I answered before, I don't want to do it server side, because too many changes are involved. Anyway, I'm doing some benchmarking, will let ya know. –  Mar 06 '14 at 19:53