Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Page 1 of 3 123 LastLast
Results 1 to 15 of 40
  1. #1
    Senior Coder
    Join Date
    Jun 2002
    Location
    near Oswestry
    Posts
    4,508
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Using the DOM before window.onload (Part II)

    There was a part one, but I can't find the thread now...

    Anyway, brief precis - DOM scripts can't be called before window.onload, because you can't rely on the DOM being useable until it's closed (the parser has finished parsing the document). However the window.onload event is synchronous with images and external dependencies, so it doesn't fire until they've all resolved (or timed out). What we really want is an event that fires when the DOM ready, without reference to external dependencies. But there isn't one.

    I'd been messing about with image onload events - trying to introduce some server latency in order to buy the time we need between the rendering of an object at the end of the </body> (the image with the onload handler) and the DOM being ready. It works, but it's a messy hack, and anyway <img onload> has been deprecated in XHTML.

    So, then I thought ... what about a timer that checks for the document and then a DOM method, and if it exists we know the DOM is ready so we can safely call our function. Like this [where the eventual function we're calling is iotbs()]
    Code:
    //DOM-ready initialisation call object (timeout-counter, wait function)
    var domReady = { 'time' : 0, 'wait' : window.setInterval(function()
    {
    	//increment the timeout-counter
    	domReady.time ++;
    	
    	//if we get to 100 (10 seconds)
    	if(domReady.time >= 100) 
    	{ 
    		//timeout the request 
    		clearInterval(domReady.wait); 
    	}
    	
    	//otherwise if the document and a DOM method exists
    	else if(typeof document != 'undefined' && typeof document.getElementsByTagName != 'undefined')
    	{
    		//call IOTBS initialisation function, if it exists
    		if(typeof iotbs == 'function') { iotbs(); }
    		
    		//timeout the request 
    		clearInterval(domReady.wait); 
    	};
    	
    },100) };
    Have I missed anything there? Is it right to assume, from the document and getElementsByTagName function existing, that the DOM is ready and all methods are available as normal, or is that a fallacy? Is there any other way it could fail?
    Last edited by brothercake; 04-07-2005 at 11:36 AM.
    "Why bother with accessibility? ... Because deep down you know that the web is attractive to people who aren't exactly like you." - Joe Clark

  • #2
    Regular Coder
    Join Date
    Aug 2004
    Location
    codegoboom@yahoo.com
    Posts
    999
    Thanks
    0
    Thanked 0 Times in 0 Posts
    I don't know, but isn't the DOM available when a script is placed just prior to </body>?
    *this message will self destruct in n-seconds*

  • #3
    Kor
    Kor is offline
    Red Devil Mod Kor's Avatar
    Join Date
    Apr 2003
    Location
    Bucharest, ROMANIA
    Posts
    8,478
    Thanks
    58
    Thanked 379 Times in 375 Posts
    a silly question... is it 100 equal with 10 seconds? Aren't there 100 miliseconds ( 0.1 seconds)?

    On the other hand... same quest as codegoboom: is'n DOM available anyway when prior to content?
    KOR
    Offshore programming
    -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*

  • #4
    Senior Coder
    Join Date
    Jun 2002
    Location
    near Oswestry
    Posts
    4,508
    Thanks
    0
    Thanked 0 Times in 0 Posts
    Quote Originally Posted by Kor
    a silly question... is it 100 equal with 10 seconds? Aren't there 100 miliseconds ( 0.1 seconds)?
    Yes .. but my timer iterates every 100 milliseconds, and it counts up 1, so 100 iterations of 100 milliseconds = 10000 milliseconds = 10 seconds

    But now I think again, maybe 15 seconds would be better.

    Quote Originally Posted by Kor
    On the other hand... same quest as codegoboom: is'n DOM available anyway when prior to content?
    No, you can't rely on methods of the DOM being available until the document has closed, which in the case of HTML means *after* the </html> tag has rendered, and the parser declares the document readyState to be "4". Shame it doesn't just report that, since all browsers have it (or something equivalent) in their internal event architecture ...

    But anyway .. if you try manipulating the DOM before then it might fail; in most cases it actually won't fail, it will work fine - but that's just luck - interpretor latency and similar delays, which are not predictable in our favour.
    Last edited by brothercake; 04-07-2005 at 11:43 AM.
    "Why bother with accessibility? ... Because deep down you know that the web is attractive to people who aren't exactly like you." - Joe Clark

  • #5
    Kor
    Kor is offline
    Red Devil Mod Kor's Avatar
    Join Date
    Apr 2003
    Location
    Bucharest, ROMANIA
    Posts
    8,478
    Thanks
    58
    Thanked 379 Times in 375 Posts
    yeap. sounds logical...

    Now, with no direct link with the thread, I wish to ask something else. I remember that you (or it was not you? - I am not able to find that thread again) showd us a tricky way to a real preloader of images. I have noticed that all the preloading code I have seen looks and acts on the presumtion that onload will fire the function when the whole page is loaded. I guess that most of the time the page loading time is not the same with full images loading time, so that those prelaoding codes are not relyable to me...

    Is there a true method to verify if a SRC element has been really loaded into the cache?
    KOR
    Offshore programming
    -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*

  • #6
    Kor
    Kor is offline
    Red Devil Mod Kor's Avatar
    Join Date
    Apr 2003
    Location
    Bucharest, ROMANIA
    Posts
    8,478
    Thanks
    58
    Thanked 379 Times in 375 Posts
    ...and I remeber that I have recently noticed that thare is even a difference between browsers in loading sequencely the DOM

    http://www.codingforums.com/showthread.php?t=55690
    KOR
    Offshore programming
    -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*

  • #7
    Senior Coder
    Join Date
    Jun 2002
    Location
    near Oswestry
    Posts
    4,508
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Part IIb - The Rewrite

    Okay .. I've had to restructure this construct quite a lot - the way it was before it was causing a crash bug in IE5.0 on Windows 2K and 98SE. It was the use of setInterval that was doing it - setTimeout was not a problem - so I've changed it to use that, but that of course means restarting the timer manually, so I need a reference to it, and hence a named (rather than anonymous) function. I've used the timeout syntax ("function()", n) rather than (function, n), because the latter doesn't work in Safari 1.0

    I also increased the attempt time to 15 seconds, and slowed it down to 250ms iterations to be less intensive. And I've added another object test, for the body element, so that the scripting can go in the head section, and because without that there were occassional errors in IE and Konqueror from the body not existing (as I suppose there would be).

    Here's the revised code. Anything else I haven't thought of that could make it untenable?

    Code:
    //DOM-ready watcher
    function domReady()
    {
    	//start or increment the counter
    	this.n = typeof this.n == 'undefined' ? 0 : this.n + 1;
    
    	//if the document, a DOM method, and the body all exist
    	if(typeof document != 'undefined' && typeof document.getElementsByTagName != 'undefined' && document.getElementsByTagName('body')[0] != null)
    	{
    	//>>>-------------------------<<<
    	//>>> DOM SCRIPTING GOES HERE <<<
    
    
    
    	//>>>-------------------------<<<
    	}
    
    	//otherwise if we haven't reached 60 (so timeout after 15 seconds)
    	else if(this.n < 60)
    	{
    		//restart the watcher
    		setTimeout('domReady()', 250);
    	}
    };
    //start the watcher
    domReady();
    In tests, this almost always runs after the first iteration, except: in IE6 roughly 1 time in 20 it takes 2 or 3 iterations; and in Konqueror it occassionally takes 7 or 8 iterations. So far it's never failed - it's never tried to run a DOM script and timed out before running, or run it and caused errors. In old browser that don't support DOM scripting it should fail cleanly - timeout after 15 seconds and do nothing; but I still have to test that in a range of legacy browsers, to make sure there's nothing evil going on.
    Last edited by brothercake; 04-12-2005 at 09:02 PM.
    "Why bother with accessibility? ... Because deep down you know that the web is attractive to people who aren't exactly like you." - Joe Clark

  • #8
    Senior Coder
    Join Date
    Jun 2002
    Location
    near Oswestry
    Posts
    4,508
    Thanks
    0
    Thanked 0 Times in 0 Posts
    Oh and another thing - if the scripting is going to modify any pre-existing HTML elements, the test condition also has to check for that:
    Code:
    //DOM-ready watcher
    function domReady()
    {
    	//start or increment the counter
    	this.n = typeof this.n == 'undefined' ? 0 : this.n + 1;
    
    	//if the document, a DOM method, and the body all exist
    	//>>> and check for any pre-existing elements the script needs: && obj != null
    	if
    	(
    		typeof document != 'undefined' 
    		&& typeof document.getElementsByTagName != 'undefined' 
    		&& document.getElementsByTagName('body')[0] != null 
    		&& document.getElementById('something') != null 
    	)
    	{//>>>-- DOM SCRIPTING GOES HERE --<<<
    
    
    
    	}//>>>-----------------------------<<<
    
    	//otherwise if we haven't reached 60 (so timeout after 15 seconds)
    	else if(this.n < 60)
    	{
    		//restart the watcher
    		setTimeout('domReady()', 250);
    	}
    };
    //start the watcher
    domReady();
    "Why bother with accessibility? ... Because deep down you know that the web is attractive to people who aren't exactly like you." - Joe Clark

  • #9
    fci
    fci is offline
    Senior Coder
    Join Date
    Aug 2004
    Location
    Twin Cities
    Posts
    1,345
    Thanks
    0
    Thanked 0 Times in 0 Posts
    I do this:
    Code:
    function Loader() {
        this.action = [];
        this.add = function(obj) {
            this.action.push(obj);
        }
        this.exec = function() {
            var i;
            for (i in this.action) {
                this.action[i]();
            }
        }
    }
    var loader    = new Loader();
    window.onload = function() { loader.exec(); };
    then when I need something to run when the page is fully loaded:
    Code:
    loader.add(function() {
    /* you can do this multiple times. */
    });
    Last edited by fci; 04-16-2005 at 05:34 AM.

  • #10
    Senior Coder
    Join Date
    Jun 2002
    Location
    near Oswestry
    Posts
    4,508
    Thanks
    0
    Thanked 0 Times in 0 Posts
    A neat technique But it still has the same core "problem" as all such wrappers - it doesn't fire until images and other dependencies have resolved or timed out, so if you have a less-than-reliable ad server, or your pages are just graphics heavy, you can be sitting there waiting for your scripts to start, when they could have started already ... if only they'd known ..

    That's the issue I'm trying to address


    I've been doing a lot of tweaking and refinement on this idea, putting it into practise with different scripts, and chatting with jkd about it, and I've discovered some interesting things:

    I'd been assuming that an element object doesn't exist until its close tag has rendered, but in fact that's not the case - an object exists as soon as its open tag exists, so a test inside an element can test for the element itself. This is fab - it means that the typeof tests for "document" and "getElementsByTagName" are unecessary, I can go straight to testing for the BODY. However I did have to keep the typeof test anyway, because that's what filters out non-DOM browsers.

    Okay, so then I discovered that in older gecko builds (testing ns7.1), if the script is in the HEAD section, the reference "document.getElementsByTagName('body')" is always a collection with zero items, and item(0) is always "undefined" (not null, curiously). If the script is put in the BODY, it can retrieve the BODY using getElementsByTagName; but in the HEAD it can only retrieve the HEAD (even after 60 iterations, and the page has long since stopped processing anything else)

    But even stranger, although this is the case, it's not the case for the reference "document.body" - that references comes back as and when expected. Bizarre. So, I had to supplement the test for getElementsByTagName('body') with this additional test for document.body, arranged so that if document.body doesn't exist at all (eg, in some browsers in XHTML mode) then it won't err or break, it will just use the first test; it will always use the first test, unless that fails; so the only gap there is old gecko builds in XHTML mode - but that's not really an issue, partly because those older builds have largely fallen by the wayside, but mostly because they retain that particular shortcut object while in XHTML mode anyway. So no worries sheila

    Ho hum .. enough of my rambling Here's the new code, first with original whitespace and commenting:
    Code:
    //DOM-ready watcher
    function domReady()
    {
    	//start or increment the counter
    	this.n = typeof this.n == 'undefined' ? 0 : this.n + 1;
    	
    	//if DOM methods are supported, and the body element exists
    	//(using a double-check including document.body, for the benefit of older moz builds [eg ns7.1]
    	//in which getElementsByTagName('body')[0] is undefined, unless this script is in the body section)
    	//>>> and any elements the script is going to manipulate exist
    	if
    	(
    		typeof document.getElementsByTagName != 'undefined' 
    		&& (document.getElementsByTagName('body')[0] != null || document.body != null)
    		//>>> && document.getElementById('something') != null
    	)
    	{
    	//>>>-- DOM SCRIPTING GOES HERE --<<<
    	
    	
    		alert("The DOM is ready!");
    
    
    	//>>>-----------------------------<<<
    	}
    
    	//otherwise if we haven't reached 60 (so timeout after 15 seconds)
    	//in practise, I've never seen this take longer than 7 iterations [in kde 3.2.2 
    	//in second place was IE6, which takes 2 or 3 iterations roughly 5% of the time]
    	else if(this.n < 60)
    	{
    		//restart the watcher
    		//using the syntax ('domReady()', n) rather than (domReady, n)
    		//because the latter doesn't work in Safari 1.0
    		setTimeout('domReady()', 250);
    	}
    };
    //start the watcher
    domReady();
    And here's the code again formatted for production use, with minimal whitespace and no comments:
    Code:
    function domReady(){this.n=typeof this.n=='undefined'?0:this.n+1;if(typeof document.getElementsByTagName!='undefined'&&(document.getElementsByTagName('body')[0]!=null||document.body!=null))
    {
    	
    	alert("The DOM is ready!");
    
    }
    else if(this.n<60){setTimeout('domReady()',250);}};domReady();
    I've tested it in every version of every browser I have (and that's a lot...) and it works in all DOM-capable browsers, or fails cleanly.
    Last edited by brothercake; 04-17-2005 at 05:32 AM.
    "Why bother with accessibility? ... Because deep down you know that the web is attractive to people who aren't exactly like you." - Joe Clark

  • #11
    fci
    fci is offline
    Senior Coder
    Join Date
    Aug 2004
    Location
    Twin Cities
    Posts
    1,345
    Thanks
    0
    Thanked 0 Times in 0 Posts
    in my case, I could move this call to the to the bottom(to before the </body> tag or whatever is 'standard'), loader.exec(), or would that not solve the problem?
    Last edited by fci; 04-17-2005 at 07:55 AM.

  • #12
    Senior Coder
    Join Date
    Jun 2002
    Location
    near Oswestry
    Posts
    4,508
    Thanks
    0
    Thanked 0 Times in 0 Posts
    Well, before this thread I would have said no, that won't work - but in fact it probably will, contrary to what I thought before: if your script is immmediately before the </body> tag and doesn't manipulate any other elements, you should be fine.

    The advantages of my method are its rechecking - so if an object doesn't exist it can wait and try again - and the fact that it can go anywhere in the document.
    Last edited by brothercake; 04-18-2005 at 03:37 PM.
    "Why bother with accessibility? ... Because deep down you know that the web is attractive to people who aren't exactly like you." - Joe Clark

  • #13
    fci
    fci is offline
    Senior Coder
    Join Date
    Aug 2004
    Location
    Twin Cities
    Posts
    1,345
    Thanks
    0
    Thanked 0 Times in 0 Posts
    have you thought of allowing your domReady function to accept a function as an argument(similar to how mine does) ? I deal more with dynamic(php, bleh) stuff. if I did static pages(for example) then your function would make more sense to me (just trying to explain my perception of the problem)

  • #14
    Senior Coder
    Join Date
    Jun 2002
    Location
    near Oswestry
    Posts
    4,508
    Thanks
    0
    Thanked 0 Times in 0 Posts
    Quote Originally Posted by fci
    have you thought of allowing your domReady function to accept a function as an argument(similar to how mine does) ? I deal more with dynamic(php, bleh) stuff. if I did static pages(for example) then your function would make more sense to me (just trying to explain my perception of the problem)
    Oh .. you mean so that it can be used a library script without having to have multiple individually-edited versions.

    So a construct that could be used like this:
    Code:
    domReady(funcName);
    Or like this
    Code:
    domReady(function()
    {
    
    });
    Is that what you mean?
    "Why bother with accessibility? ... Because deep down you know that the web is attractive to people who aren't exactly like you." - Joe Clark

  • #15
    fci
    fci is offline
    Senior Coder
    Join Date
    Aug 2004
    Location
    Twin Cities
    Posts
    1,345
    Thanks
    0
    Thanked 0 Times in 0 Posts
    yes. your current script isn't flexible enough for the dynamic needs that exist(in my case, at least). I'll probably add a DOM check in what I wrote as a result of this thread. you'll also need to modify your setTimeout call.


  •  
    Page 1 of 3 123 LastLast

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •