28

I'm a bit confused as to when the window.onload event is fired. For example: i have a page that has lots of external js files and even an on-demand loading of the script (dynamically creating a tag). All of this code is in the page (ie. it does not get fired on click or smth, it should execute while loading). Now let's say that i have window.onload = somefunction() in the last on-demand javascript. Is it possible that window.onload will fire before all the scripts actually get loaded?

André Pena
  • 48,518
  • 37
  • 172
  • 216
Marius S.
  • 479
  • 2
  • 5
  • 9

2 Answers2

25

window.onload (a.k.a body.onload) gets fired after the main HTML, all CSS, all images and all other resources have been loaded and rendered. So if your images stall, that can take some time.

If you just need the HTML (DOM), you can use jQuery's $(document).ready() - it will fire when the HTML has been parsed but before the browser has finished loading all external resources (images and style sheets that come after your script element in the HTML).

Scripts embedded in the page get executed when the browser parses the </script> of each. So to execute a script before any other script, add a <script> tag in the header just after <head>.

This means you can "emulate" window.onload by adding a <script> tag as the last element of the <body>.

Community
  • 1
  • 1
Aaron Digulla
  • 297,790
  • 101
  • 558
  • 777
  • Whilst script is a blocking call, is it really as basic as that, I thought onload waited until all the referenced resources had downloaded too. So if you had a reference to the tracking image used by web trends or HBX that took a while to process or justa slow loading resource (a large image?) the onload event would not fire until both the HTML had been parsed and the resources that called downloaded. – Paul Hadfield Aug 19 '10 at 10:29
  • 4
    @Paul is correct. *window.onload* doesn't fire when the browser parses ` – Andy E Aug 19 '10 at 10:36
  • er, *DOMContentLoaded*, not *DOMReady* :) – Andy E Aug 19 '10 at 10:43
  • References anyone? I'm pretty sure JS runs before the images are loaded and it surely runs before background images are loaded. This is why people add code to preload images in JS: To force the browser to load the images earlier. – Aaron Digulla Aug 19 '10 at 14:06
  • @Aaron: I can only point you to the [MDC window.onload documentation](https://developer.mozilla.org/en/DOM/window.onload), since the event isn't defined in any specification (as far as I'm aware). You can also run the example page I provided in my answer, which shows the *onload* event is fired before the dynamically added script is parsed. – Andy E Aug 19 '10 at 14:12
  • Hmmm... I'm noticing that you're talking about "window.onload". Is that the same as "body.onload" or are they fired at different times? – Aaron Digulla Aug 19 '10 at 14:27
  • @Andy: How about images? Are they loaded, too? At least images which are defined with CSS "background: url();" load after onload (I mean the image object is there but they might be rendered several seconds later when the image data arrives). – Aaron Digulla Aug 19 '10 at 14:29
  • 1
    *body.onload* and *window.onload* are the same - *body.onload* is provided as a means to set the *window.onload* handler directly through the HTML `` element, using the *onload* attribute. *onload* won't fire until all images are downloaded and rendered too. I'm *fairly* sure this applies to CSS images too. – Andy E Aug 19 '10 at 14:42
  • @Andy: Thanks for the info about unload. As for images, I really doubt that the browser waits for them to load. Maybe it doesn't matter since the web is so fast today that we rarely have to wait for them but a few years ago, images were loaded after the HTML in background threads and I'm pretty sure that JS was running by then. Can't prove it, though (no time :-( ) – Aaron Digulla Aug 19 '10 at 15:12
  • @Aaron: I think we might be on different pages here. JS runs before the document loads, there's no doubt about that. JS is executed *immediately* after the script block containing it is parsed. The question is regarding *window.onload*, which won't fire until after images have downloaded. – Andy E Aug 19 '10 at 15:34
  • 1
    well window.onload and jquery's $(document.ready()) are not the same thing as response here implies ... One fires when all loaded (images and DOM), latter fires when DOM is ready – armyofda12mnkeys Apr 01 '13 at 17:21
  • @armyofda12mnkeys: Thanks for the clarification. I've updated my answer. – Aaron Digulla Apr 03 '13 at 07:43
6

No. window.onload() is invoked when all resources (the document, objects, images, css, etc) have finished rendering.

Misread the question. Yes, it is entirely possible that the window.onload event will fire before a dynamically appended script has finished downloading. Scripts added using the DOM (document.createElement()) download asynchronously and aren't subject to the usual rule that window.onload() waits for all resources to finish downloading first.

I set up a test suite for you, http://jsfiddle.net/ywSMW/. This script adds the jQuery script to the DOM dynamically and writes the value of $ to the console during the onload handler. It then writes the value again a second later. Even with the script being cached, the first write to the console returns undefined, meaning the onload even has fired before the jQuery script has been downloaded and parsed.

Tested in IE and Chrome.


Re: the comments, if you want to check if the onload event has already fired, you can set the value of a global variable inside the onload handler:
var windowHasLoaded = false;

window.onload = function () {
    windowHasLoaded = true;
}

function doSomethingWhenWindowHasLoaded() {
    if (!windowHasLoaded) {
        // onload event hasn't fired yet, wait 100ms and check again 
        window.setTimeout(doSomethingWhenWindowHasLoaded, 100);
    } else {
        // onload event has already fired, so we can continue
    }        
}        
Andy E
  • 311,406
  • 78
  • 462
  • 440
  • Is there any way i could test in the script if the window has already been loaded? – Marius S. Aug 19 '10 at 10:38
  • 1
    @Marius S: yes, you can check the *document.readyState* property. When the document is parsed, it has a value of `"loaded"`. After the *onload* has fired, it has a value of `"complete"`. – Andy E Aug 19 '10 at 10:47
  • But readyState isn't supported in all browsers. This is the reason i'm asking. – Marius S. Aug 19 '10 at 10:51
  • @Marius: which browsers are you talking about? *document.readyState* is supported in IE, Firefox, Chrome, Safari and Opera. – Andy E Aug 19 '10 at 10:57
  • @Marius: w3c doesn't maintain browser compatibility references. You might be confusing w3c for W3Schools. Firefox *does* support it, although only in version 3.6 and later. The simplest solution otherwise is to create a global variable, e.g. `var loaded;`, then in the *onload* event handler, set that variable to *true*. Accessing that variable from anywhere else in the code will yield *true* when the onload event has already fired. – Andy E Aug 19 '10 at 13:04
  • @AndyEarnshaw can we force the document to wait for the dynamic scripts to finish loading then complete its process, lets say am loading angularjs dynamically and if I did it in the normal way, the ng-app will crash as angular didn't finish loading yet !! onload and DOMContentLoaded will not wait for dynamic script ! any alternative ! – Amgad Fahmi Oct 16 '16 at 19:44
  • @AmgadFahmi use defer or async attributes, watch this video at 7:49 https://www.youtube.com/watch?v=vAgKZoGIvqs&t=515s , althougt I would recomend to watch all that video because it's amazing – John Balvin Arias Aug 28 '18 at 09:42