window.onload seems to trigger before the DOM is loaded (JavaScript)
Asked Answered
G

5

13

I am having trouble with the window.onload and document.onload events. Everything I read tells me these will not trigger until the DOM is fully loaded with all its resources, it seems like this isn't happening for me:

I tried the following simple page in Chrome 4.1.249.1036 (41514) and IE 8.0.7600.16385 with the same result: both displayed the message "It failed!", indicating that myParagraph is not loaded (and so the DOM seems incomplete).

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
    <head>
        <script type="text/javascript">
            window.onload = doThis();
            // document.onload gives the same result

            function doThis() {
                if (document.getElementById("myParagraph")) {
                    alert("It worked!");
                } else {
                    alert("It failed!");
                }
            }
        </script>
    </head>

    <body>
        <p id="myParagraph">Nothing is here.</p>
    </body>
</html>

I am using more complex scripts than this, in an external .js file, but this illustrates the problem. I can get it working by having window.onload set a timer for half a second to run doThis(), but this seems like an inelegant solution, and doesn't answer the question of why window.onload doesn't seem to do what everyone says it does. Another solution would be to set a timer that will check if the DOM is loaded, and if not it will just call itself half a second later (so it will keep checking until the DOM is loaded), but this seems overly complex to me.

Is there a more appropriate event to use?

Gemmule answered 20/3, 2010 at 23:56 Comment(3)
First mistake that I see is that you assing [function result] instead of [function] itself. Can you see doThis() is a statement that returns undefined after evaluation because doThis has no return operator. window.onload = doThis; will do the job. Note there are no parenthesArbela
@DavidMason W3Schools is a poor source of information. They are not affiliated with the W3C in any way. Do not treat w3schools as an authoritative source of information, treat them the way they deserve to be treated: nuisance links that you have to skip over when you search for a real reference website.Recluse
@Recluse present-day me agrees completely. I recommend w3fools.com for anyone who is unsure. I tend to go straight for developer.mozilla.org for high quality info these days, then do a more extensive search if I don't find what I'm looking for there (which is generally when I'm trying to do something ridiculous). I'm pretty embarrassed that past-me posted that... but I can delete it! There, one less naive reference to w3schools on the Internet :) Thanks for spotting it.Gemmule
R
10

At the time window is loaded the body isn't still loaded therefore you should correct your code in the following manner:

<script type="text/javascript">
    window.onload = function(){
        window.document.body.onload = doThis; // note removed parentheses
    };

    function doThis() {
        if (document.getElementById("myParagraph")) {
            alert("It worked!");
        } else {
            alert("It failed!");
        }
    }
</script>

Tested to work in FF/IE/Chrome, although thinking about handling document.onload too.

As already mentioned, using js-frameworks will be a far better idea.

Runoff answered 21/3, 2010 at 0:14 Comment(6)
Thanks, that does seem to solve my problem, and solves what I thought was a recursion of the same problem of attaching something to the body.onload event before knowing if the body has been successfully loaded. I now have the message "It worked!" popping up, and can continue pedantically keeping my scripts and markup nice and separate.Gemmule
Note that using this approach for 2 scripts will probably overwrite one with the other. These days I tend to use document.addEventListener("DOMContentLoaded", function(event) { console.log("DOM fully loaded and parsed"); }); See: developer.mozilla.org/en-US/docs/Web/Reference/Events/…Gemmule
@DavidMason DomContentLoaded was loading before onload in my tests. Sometimes the speechSynthesis.getVoices() was an empty array on the load event and on the DOMContentLoaded event. Is there a later event?Federative
@1.21gigawatts I don't know anything about how your speechSynthesis.getVoices() is supposed to be loaded so looking for content load may not be the thing to do - if there's a script loading it then you need your script that attempts to use it to appear after that script (and not have that script marked as async).Gemmule
@DavidMason SpeechSynthesis is a property on the windows object. The getVoices call gets a list of text to speech voices. Sometimes it was empty. A simple page refresh and it was available. What I did to work around it was make the call first on dom content load and on load and assign it to an array and then later if the user accesses the voices array I check if the array is empty and call it again a second time. That seemed to do it. developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesisFederative
Just for the record, nothing mentioned in any of these answers or comments has worked for me. No matter what I try, the "load" triggers like 2 seconds before the body of the page appears. I have just settled on adding a 3 second timeout after the "load" trigger. it's klugey and not guaranteed, but it's better than nothing.Parahydrogen
L
10

Just use window.onload = doThis; instead of window.onload = doThis();

Lamentation answered 4/6, 2010 at 12:13 Comment(1)
for more information why, see this: #8830574Thickleaf
F
9

It's important to understand that () is an operator, just like + or &&. () Takes a function and calls it.

So in that case, doThis is a function object, and () is the operator that calls the function. doThis() combined to together calls doThis, executes it, and evaluates to the return value of doThis

So window.onload = doThis() is basically assigning the return value of doThis to window.onload

And thus, to fix that, you need to reference the function itself, not call it.

Do window.onload = doThis

Fungistat answered 4/7, 2016 at 2:17 Comment(1)
This should be the answer.Immunize
O
1

Have you tried using a javascript library instead, e.g. jQuery and it's $(document).ready() function:

  $(document).ready(function() {
      // put all your jQuery goodness in here.
  });
Oresund answered 21/3, 2010 at 0:0 Comment(4)
Thanks, I'll check that out this week. I'm still concerned that there doesn't seem to be any event associated with the DOM that can reliably tell me when the DOM has loaded, without resorting to third-party scripts.Gemmule
It is definitely overkill to add a library just for this - the library download adds latency and data transfer and probably only saves you a few characters. jQuery is particularly heavyweight. Having said that, if you're already using a library for other things there's probably little or no harm in using it to handle attaching a function to the dom-ready event.Gemmule
@David Mason I totally agree. Most cases, i have found jquery DOUBLES page load time..Muss
@JamesWalker if you load jquery (or any other popular javascript library) from a CDN, then chances are big that your browser already has the js files in its cache (from visits to other web sites), thus load time should not increase noticeably.Oresund
K
1

It depends where you put the onload function (head or body tag or further down), with internal event binding seeemingly slightly different in different browsers.

See also window.onload vs document.onload

Kibitka answered 10/9, 2011 at 12:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.