Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

DOM ready, window.onload, etc.

20 views
Skip to first unread message

Hans-Georg Michna

unread,
Dec 28, 2009, 8:55:51 AM12/28/09
to
Hi everybody; hope you all got over Xmas in good shape.

The following may be a frequently asked question, but I haven't
seen any inspiring answer.

Does anybody here have a good idea or some simple working code
to solve the problem of having JavaScript code work on the DOM
just after it is loaded? window.onload has the obvious problem
that it waits for inessential content like images and can
therefore be very late.

Resig & Co. have a working method in jQuery, but it relies on
browser sniffing and several browser-specific ways. Obviously
this is not guaranteed to work in future browsers and may need
regular updates.

I am particularly looking for a method that can be done only in
JavaScript, without having to have any dedicated HTML code
embedded in documents.

It seems that there can be no perfection here, so a method that
works in 99% of all cases will have to be good enough.

I'm thinking along the lines of checking the document body and
waiting until it is stable for a short time like a second. Not a
heavenly solution, but at least totally browser-independent.

I have already tried to append a tiny child node inside the body
and then checking one of its rendering parameters, but the
method will probably have to be refined, for example by checking
that no new elements are added after it because the DOM is still
being built up.

How about checking some parameter of the document body in
regular, relatively slow intervals, like the total number of
nodes or some such? Browsers that allow JavaScript to access the
DOM before it is completely built should yield a rising, then
stabilizing number. Or perhaps the identity of the last node
could be checked, assuming that the DOM is always built
sequentially from HTML code. I need to do this only for web
pages over which I have at least some control and whose HTML
structure I know.

Of course the JavaScript code should at the same time wait for
window.onload as a last resort.

Not sure if this is possible in any decent quality at all, but
I'd like to give it a try if I see a chance.

Hans-Georg

JR

unread,
Dec 28, 2009, 5:00:30 PM12/28/09
to
On Dec 28, 11:55 am, Hans-Georg Michna <hans-

georgNoEmailPle...@michna.com> wrote:
> Hi everybody; hope you all got over Xmas in good shape.
>
> The following may be a frequently asked question, but I haven't
> seen any inspiring answer.

I didn't find any entry about that in the c.l.js FAQ.

Dean Edwards addressed the 'window.onload' problem in his [we]blog:
http://dean.edwards.name/weblog/2005/09/busted/
http://dean.edwards.name/weblog/2006/06/again/

But his 'solution' is still incomplete - it covers only IE, Safari and
Firefox (versions available in 2006).

Yahoo has the 'onDOMReady' method:
http://developer.yahoo.com/yui/event/#ondomready

Cheers,
JR

David Mark

unread,
Dec 28, 2009, 7:20:04 PM12/28/09
to
On Dec 28, 5:00 pm, JR <groups_j...@yahoo.com.br> wrote:
> On Dec 28, 11:55 am, Hans-Georg Michna <hans-
>
> georgNoEmailPle...@michna.com> wrote:
> > Hi everybody; hope you all got over Xmas in good shape.
>
> > The following may be a frequently asked question, but I haven't
> > seen any inspiring answer.
>
> I didn't find any entry about that in the c.l.js FAQ.

There isn't one.

For God's sake, don't listen to him. :(

>
> But his 'solution' is still incomplete - it covers only IE, Safari and
> Firefox (versions available in 2006).

It was bullshit then and it is bullshit now. It is known to cause
Operation Aborted errors. IIRC, jQuery figured this out recently
(three years later). Search their archive.

>
> Yahoo has the 'onDOMReady' method:http://developer.yahoo.com/yui/event/#ondomready

I'm sure that's nonsense too. The fact is that there is no way to do
it in IE. You can use a timeout at the very bottom of the document
(just before the closing BODY tag). But that's no guarantee against
the Operation Aborted show-stopper. The "frameworks" don't like that
though as they seem to think their users are too stupid to use
conditional comments, preferring a "cool" hack that "just works" (most
of the time). ;)

So design your documents/apps in accordance with this reality (i.e.
don't use too many images, Flash movies, etc.) That's it.

JR

unread,
Dec 28, 2009, 7:51:16 PM12/28/09
to
> > Dean Edwards addressed the 'window.onload' problem in his [we]blog:http://dean.edwards.name/weblog/2005/09/busted/http://dean.edwards.na...

>
> For God's sake, don't listen to him.  :(
>
>
>
> > But his 'solution' is still incomplete - it covers only IE, Safari and
> > Firefox (versions available in 2006).
>
> It was bullshit then and it is bullshit now.  It is known to cause
> Operation Aborted errors.  IIRC, jQuery figured this out recently
> (three years later).  Search their archive.

Well, Dean Edwards' attempt was more like an incomplete search for a
solution. I think he has given it up, since it's an 2006 entry in his
blog.

> > Yahoo has the 'onDOMReady' method:http://developer.yahoo.com/yui/event/#ondomready
>
> I'm sure that's nonsense too.  The fact is that there is no way to do
> it in IE.  You can use a timeout at the very bottom of the document
> (just before the closing BODY tag).  But that's no guarantee against
> the Operation Aborted show-stopper.  The "frameworks" don't like that
> though as they seem to think their users are too stupid to use
> conditional comments, preferring a "cool" hack that "just works" (most
> of the time).  ;)
>
> So design your documents/apps in accordance with this reality (i.e.
> don't use too many images, Flash movies, etc.)  That's it.

Thanks for that hint!

Cheers,
JR

Garrett Smith

unread,
Dec 28, 2009, 7:58:50 PM12/28/09
to
Hans-Georg Michna wrote:
> Hi everybody; hope you all got over Xmas in good shape.
>
I finished in good shape.

> The following may be a frequently asked question, but I haven't
> seen any inspiring answer.
>
> Does anybody here have a good idea or some simple working code
> to solve the problem of having JavaScript code work on the DOM
> just after it is loaded?

What is the problem you want to solve that makes this seem an attractive
solution?
--
Garrett
comp.lang.javascript FAQ: http://jibbering.com/faq/

JR

unread,
Dec 29, 2009, 6:55:13 AM12/29/09
to

There is an excellent article in Peter Michaux's site about the
window.onload problem - it also states that a robust technique for
early page enlivenment is not possible across the big four browsers
(IE, Safari, Mozilla and Opera). The link to that article goes below:
http://peter.michaux.ca/articles/the-window-onload-problem-still

But, in a later article, Peter has dropped the ball when he said that
the problem was solved by - believe it or not - jQuery, which uses the
"Dean Edwards' technique". I can see David Mark really furious... OMG.
http://peter.michaux.ca/articles/the-window-onload-problem-really-solved

All in all, I'll stick with David's advice. But I am waiting for his
comments on myLibrary's documentReady.

Cheers,
JR

David Mark

unread,
Dec 30, 2009, 1:23:12 AM12/30/09
to

That's an outdated article.

>
> All in all, I'll stick with David's advice. But I am waiting for his
> comments on myLibrary's documentReady.

I haven't looked at that "add-on" script in years. Not proud of it at
all (and will likely clean it up a bit before the year's out).

Basically, it is an extra (optional) script that you put at the very
end of the document (before the closing BODY tag). A timeout is used
for IE (using conditional compilation). I also see it has some extra
baggage that can be removed.

It also detects the readyState property and polls it when available.
Pretty hack-y, but it's a rock compared to the Dean Edwards hack (or
this new doScroll abomination).

My recommendation is to avoid such things (mine or otherwise).

http://www.cinsoft.net/mylib-doc0.html#core

And one caveat. Though I have never had any problems with it and
have tested a ton of browsers/configurations (not proof of anything,
of course), Kangax reported that he had a problem with the test page
with the new Konquerer (not sure if it was a release version or not).
IIRC, the document ready listener was entered while document.body was
null (as if the HEAD were still parsing). Either that or this
function is failing (very) unexpectedly.

getBodyElement = function(docNode) {
docNode = docNode || global.document;
if (isRealObjectProperty(docNode, 'body')) { return
docNode.body; }
if (typeof getEBTN == 'function') { return getEBTN('body',
docNode)[0] || null; }
return null;
};

I can't imagine the problem has anything to do with a script at the
_end_ of the BODY (more likely there was a problem with the
DOMContentLoaded event). As I don't care to build Konquerer, I'll
offer a free license to anyone who can reproduce the problem. If I
made a mistake, I'll be the first to admit it (and will fix it without
argument). :)

http://www.cinsoft.net/mylib-builder.asp

JR

unread,
Dec 30, 2009, 7:16:30 AM12/30/09
to

Man, I was really hoping for a professional answer like that! Thanks a
lot for clarifying my doubts.

--
JR

Hans-Georg Michna

unread,
Dec 31, 2009, 9:36:58 AM12/31/09
to
On Mon, 28 Dec 2009 16:58:50 -0800, Garrett Smith wrote:

>Hans-Georg Michna wrote:

>> Hi everybody; hope you all got over Xmas in good shape.

>I finished in good shape.

Ha! So now for switching years!

>> The following may be a frequently asked question, but I haven't
>> seen any inspiring answer.
>>
>> Does anybody here have a good idea or some simple working code
>> to solve the problem of having JavaScript code work on the DOM
>> just after it is loaded?

>What is the problem you want to solve that makes this seem an attractive
>solution?

Putting a table of contents into a web page, particularly inside
a Content Management System, that is clickable and chapters
reachable from the outside. The many known TOC scripts don't do
all of this.

I'm now thinking about a relatively simple solution that will
work well in many newer browsers and will still work in all
others through window.onload. The basic idea is to put event
handlers on both events if possible, then remove them from both
as soon as one of them fires, while leaving any foreign handlers
in place (except for window.onload, which we want to fire only
once anyway).

function waitForDom() {
// Keep preexisting handler and append own handler:
var precedingOLHandler = window.onload;
// Try readyState if the browser has it:
if (document.readyState) {
function waitForDom.isDocumentReady() {
return document.readyState === "interactive" ||
document.readyState === "complete";
}
if (waitForDom.isDocumentReady()) {
doTheActualWork();
return;
}
var precedingORSCHandler = document.onreadystatechange;
document.onreadystatechange = function () {
if (precedingORSCHandler) precedingORSCHandler();
if (waitForDom.isDocumentReady()) {
// Reset handlers, remove own handlers:
document.onreadystatechange = precedingORSCHandler;
window.onload = precedingOLHandler;
fillToc();
}
}
}
// Use window.onload also, for all other browsers:
window.onload = function () {
if (precedingOLHandler) precedingOLHandler();
// Reset handlers, remove own handlers:
if (document.readyState)
document.onreadystatechange = precedingORSCHandler;
window.onload = null;
doTheActualWork();
}
}

Have not thoroughly tested this and may come up with
improvements. Have thought a while about the closures on the old
handlers, but the entire program should be garbage-collected
anyway, after it is done. I'm not very experienced yet in these
things. Anyway, this looks much cleaner than the Dean Edwards
code, but will probably still work in many browsers, at least
once Firefox 3.6 (with document.readyState) is gaining
acceptance.

It is interesting to notice how certain inventions like
document.readyState or, for example, element.innerHTML gain
universal acceptance without being formally standardized. The
downside is that it is not enough to read the standard.

Hans-Georg

Hans-Georg Michna

unread,
Dec 31, 2009, 6:22:48 PM12/31/09
to
It didn't quite work. document.readyState === "interactive"
happens already when the DOM barely exists and is by no means
complete.

Has anybody seen any specification of whether "complete" happens
before window.onload? Or do they happen at roughly the same
time? If the latter, then I could simply use window.onload only.

Currently I use this:

function waitForDomComplete() {


// Keep preexisting handler and append own handler:
var precedingOLHandler = window.onload;

// Use readyState if the browser has it:
if (document.readyState) {
if (document.readyState === "complete") {


doTheActualWork();
return;
}
var precedingORSCHandler = document.onreadystatechange;
document.onreadystatechange = function () {
if (precedingORSCHandler) precedingORSCHandler();

if (document.readyState === "complete") {


// Reset handlers, remove own handlers:
document.onreadystatechange = precedingORSCHandler;
window.onload = precedingOLHandler;

doTheActualWork();


}
}
}
// Use window.onload also, for all other browsers:
window.onload = function () {
if (precedingOLHandler) precedingOLHandler();
// Reset handlers, remove own handlers:
if (document.readyState)
document.onreadystatechange = precedingORSCHandler;
window.onload = null;
doTheActualWork();
}
}

I think it is quite possible that I'm doing far too much, and a
simpler piece of code would have nearly or entirely the same
effect.

Hans-Georg

David Mark

unread,
Dec 31, 2009, 6:43:45 PM12/31/09
to
On Dec 31, 6:22 pm, Hans-Georg Michna <hans-

There's one big flaw I see: IE. Nothing in that will make IE call
back before the load event is fired.

Garrett Smith

unread,
Dec 31, 2009, 7:00:29 PM12/31/09
to
Hans-Georg Michna wrote:
> On Mon, 28 Dec 2009 16:58:50 -0800, Garrett Smith wrote:
>
>> Hans-Georg Michna wrote:
>
>>> Hi everybody; hope you all got over Xmas in good shape.
>
>> I finished in good shape.
>
> Ha! So now for switching years!
>

I'll go do some heavy deadlifts and snatches. Hows that sound?

>>> The following may be a frequently asked question, but I haven't
>>> seen any inspiring answer.
>>>
>>> Does anybody here have a good idea or some simple working code
>>> to solve the problem of having JavaScript code work on the DOM
>>> just after it is loaded?
>
>> What is the problem you want to solve that makes this seem an attractive
>> solution?
>
> Putting a table of contents into a web page, particularly inside
> a Content Management System, that is clickable and chapters
> reachable from the outside. The many known TOC scripts don't do
> all of this.
>

If the links are included in the markup, you won't need a script at all.
That can all be done on the server. What is the reason for not adding
the links to the markup?

When you say "chapters reachable from the outside", you mean that a
fragment identifier may linking to a chapter.

<div id="chapter1"> ... </div>

[snip code]

The example code, the callback for document.onreadystatechange changes
context from document to window.

document.readyState doesn't quite work so well in IE. "interactive"
means the element is loading and "complete" fires just before onload.

> Have not thoroughly tested this and may come up with
> improvements. Have thought a while about the closures on the old
> handlers, but the entire program should be garbage-collected
> anyway, after it is done. I'm not very experienced yet in these
> things. Anyway, this looks much cleaner than the Dean Edwards
> code, but will probably still work in many browsers, at least
> once Firefox 3.6 (with document.readyState) is gaining
> acceptance.
>

Given that existing implementations of IE will be around for quite some
time, detecting the presence of a document.readyState property won't
mean much of value for you.

you'll know it's done when readyState == "complete", but in IE,
readyState == "complete" is late and readyState "interactive" will give
you early results.

> It is interesting to notice how certain inventions like
> document.readyState or, for example, element.innerHTML gain
> universal acceptance without being formally standardized. The
> downside is that it is not enough to read the standard.
>

The closest thing to a document.readyState standard is in HTML 5
| document . readyState
|
| Returns "loading" while the Document is loading, and "complete" once
| it has loaded.
|
| The readystatechange event fires on the Document object when this
| value changes.

document.readyState is not reliable.

Hans-Georg Michna

unread,
Jan 1, 2010, 1:38:39 PM1/1/10
to
On Thu, 31 Dec 2009 15:43:45 -0800 (PST), David Mark wrote:

>There's one big flaw I see: IE. Nothing in that will make IE call
>back before the load event is fired.

Not too bad. If IE doesn't, at least Firefox 3.6 will, or so I
hope.

I could scale this down and use only window.onload, which may be
the most sensible thing to do at the moment. Or I may just leave
the readyState stuff in there, as it doesn't do any harm and may
work increasingly better on new browsers. My impression is that
document.readyState is on a good way to becoming a standard, at
least a de facto one.

The big question is whether document.readyState === "complete"
comes before all the images and other things are loaded. If not,
then I don't gain anything over window.onload.

Hans-Georg

Hans-Georg Michna

unread,
Jan 1, 2010, 1:38:39 PM1/1/10
to
On Thu, 31 Dec 2009 16:00:29 -0800, Garrett Smith wrote:

>If the links are included in the markup, you won't need a script at all.
>That can all be done on the server. What is the reason for not adding
>the links to the markup?

There's a number of reasons. One is that the text may live on a
Content Management System and can be modified. Each modification
would require conscientious adaptation of the TOC code, which
not every CMS user may be up to. Another is that somebody puts a
web page somewhere and wants a table of contents quickly without
having to write more than a line of code or maybe four.

I have thought for years about an XSLT solution. As all modern
browsers contain an XSLT engine, it would be relatively easy to
do for existing XHTML pages, merely by adding an xsl:stylesheet
tag, but somehow I never got to it, even though XSLT is among my
favorite programming languages.

However, an XSLT solution would effectively be almost perfectly
equivalent to a JavaScript solution. Both pull in a code file,
which transforms the HTML page. With the additional flexibility
my program offers, I feel that it is a bit easier to write in
JavaScript than in XSLT.

>When you say "chapters reachable from the outside", you mean that a
>fragment identifier may linking to a chapter.
>
><div id="chapter1"> ... </div>

Exactly, except my code wants <h1 id="chapter1"> ... </h1> or
<h2> or <h3> etc. The code is now finished and available at
http://winhlp.com/node/682 in unreadable form (packed), but I
wouldn't mind much giving out the readable, commented source
code if anybody here were interested. After all my experience
with JavaScript is limited to some recent work, and I wouldn't
mind hints resulting from code reviews.

The same page also shows an example of the TOC.

To let a link like http://winhlp.com/node/682#n work requires a
little magic behind the scenes, as that link does not yet exist
when the page is called up and opened. Therefore the TOC code
has to do the jump, and it has to do it after it has built the
TOC and put in the chapter links. Not really difficult, but all
the other TOC scripts I found somewhere in the web didn't do
that.

>The example code, the callback for document.onreadystatechange changes
>context from document to window.

Oops, didn't even notice. What's the simplest way to do it
better? How do you even know what the original context was?

Of course there is always the hope that the context does not
matter.

>document.readyState doesn't quite work so well in IE. "interactive"
>means the element is loading and "complete" fires just before onload.

That's what I feared. Strange that somebody should invent such a
state information and even an apparently useful event, but
neglects to indicate the most interesting point in time, namely
when the DOM is completely built, but before secondary files are
loaded. How stupid would that be?

I couldn't find any precise documentation for the states. Looked
at the MSDN docs, but they are singularly imprecise.

>Given that existing implementations of IE will be around for quite some
>time, detecting the presence of a document.readyState property won't
>mean much of value for you.
>
>you'll know it's done when readyState == "complete", but in IE,
>readyState == "complete" is late and readyState "interactive" will give
>you early results.

The code failed with "interactive" on IE 8. Apparently that
event happens when the DOM root is established, but not yet much
of its content. Had to use "complete" to make it work at all
and, as you say, that may be useless when I have to use
window.onload anyway. But we can't be sure how future
implementations will behave. There is always hope. (:-)

>> It is interesting to notice how certain inventions like
>> document.readyState or, for example, element.innerHTML gain
>> universal acceptance without being formally standardized. The
>> downside is that it is not enough to read the standard.

>The closest thing to a document.readyState standard is in HTML 5
>| document . readyState
>|
>| Returns "loading" while the Document is loading, and "complete" once
>| it has loaded.
>|
>| The readystatechange event fires on the Document object when this
>| value changes.

The question remains, what exactly "complete" means. With images
or without?

>document.readyState is not reliable.

Since some browsers don't have it at all, I have to use
window.onload as a fallback anyway.

I append the current version of the code below. It relies on
closure quite a bit.

Hans-Georg

(function () {
(function waitForDomComplete() {


// Keep preexisting handler and append own handler:
var precedingOLHandler = window.onload;

// Use readyState if the browser has it and begin the
// job immediately if the DOM is already complete:


if (document.readyState) {
if (document.readyState === "complete") {

fillToc();


return;
}
var precedingORSCHandler = document.onreadystatechange;
document.onreadystatechange = function () {
if (precedingORSCHandler) precedingORSCHandler();

if (document.readyState === "complete") {


// Reset handlers, remove own handlers:
document.onreadystatechange = precedingORSCHandler;
window.onload = precedingOLHandler;
fillToc();
}
}
}
// Use window.onload also, for all other browsers:
window.onload = function () {
if (precedingOLHandler) precedingOLHandler();
// Reset handlers, remove own handlers:
if (document.readyState)
document.onreadystatechange = precedingORSCHandler;
window.onload = null;

fillToc();
}
}());

function fillToc() {
// Do the work
}
// More function definitions here
}());

Garrett Smith

unread,
Jan 1, 2010, 6:36:22 PM1/1/10
to
Hans-Georg Michna wrote:
> On Thu, 31 Dec 2009 16:00:29 -0800, Garrett Smith wrote:
>
>> If the links are included in the markup, you won't need a script at all.
>> That can all be done on the server. What is the reason for not adding
>> the links to the markup?
>
> There's a number of reasons. One is that the text may live on a
> Content Management System and can be modified. Each modification
> would require conscientious adaptation of the TOC code, which
> not every CMS user may be up to. Another is that somebody puts a
> web page somewhere and wants a table of contents quickly without
> having to write more than a line of code or maybe four.
>
> I have thought for years about an XSLT solution. As all modern
> browsers contain an XSLT engine, it would be relatively easy to
> do for existing XHTML pages, merely by adding an xsl:stylesheet
> tag, but somehow I never got to it, even though XSLT is among my
> favorite programming languages.
>

Yes doing it on the server in XSLT would result in degradable links. For
a public site with users of any browser, and for search engines, that
can help.

The onload callback will interfere user interaction momentarily.

[...]


[...]

>> The example code, the callback for document.onreadystatechange changes
>> context from document to window.
>
> Oops, didn't even notice. What's the simplest way to do it
> better? How do you even know what the original context was?
>

The base object is document. When the `document.onreadystatechange` is
called, the base object determines the `this` value. If the base object
is an activation object or null, then null is used for [[Call]].

If the browser calls document.onreadystatechange, then it may provide a
different `this` value, as it does with some BODY event handlers, but
that doesn't happen here.

document.onreadystatechange = function(){
alert(this.nodeName);
};

elerts "#document"

When the function's internal [[Call]] property is invoked, if the `this`
value is not an object (null is not an object), then the `this` value is
the global object. Saving the value of document.onreaystatechange in an
identifier, the identifier gets the functional value. When the call
operator is used on that identifier, the base object is null and so the
this value is the global object.

var oldReadyHandler = document.onreadystatechange;

document.onreadystatechange = function(){
oldReadyHandler();
alert(this.nodeName);
};

"window"
"document"

(possibly multiple times).

|11.2.3 Function Calls
|
| The production CallExpression : MemberExpression Arguments is
| evaluated as follows:
|
| 1. Evaluate MemberExpression.
| 2. Evaluate Arguments, producing an internal list of argument values
| (see 11.2.4).
| 3. Call GetValue(Result(1)).
| 4. If Type(Result(3)) is not Object, throw a TypeError exception.
| 5. If Result(3) does not implement the internal [[Call]] method, throw
| a TypeError exception.
| 6. If Type(Result(1)) is Reference, Result(6) is GetBase( Result(1)).
| Otherwise, Result(6) is null.
| 7. If Result(6) is an activation object, Result(7) is null. Otherwise,
| Result(7) is the same as Result(6).
| 8. Call the [[Call]] method on Result(3), providing Result(7) as the
| this value and providing the list Result(2) as the argument values.
| 9. Return Result(8).
|
| The production CallExpression : CallExpression Arguments is evaluated
| in exactly the same manner, except that the contained CallExpression
| is evaluated in step 1.
|
| NOTE
| Result(8) will never be of type Reference if Result(3) is a native
| ECMAScript object. Whether calling a host object can return a value of
| type Reference is implementation-dependent.


The relevant step is step 7.

| 7. If Result(6) is an activation object, Result(7) is null. Otherwise,
| Result(7) is the same as Result(6).

[...]

>
>> The closest thing to a document.readyState standard is in HTML 5
>> | document . readyState
>> |
>> | Returns "loading" while the Document is loading, and "complete" once
>> | it has loaded.
>> |
>> | The readystatechange event fires on the Document object when this
>> | value changes.
>
> The question remains, what exactly "complete" means. With images
> or without?
>

Doesn't say and since the most recent browsers vary that's a good thing.
Otherwise they would be creating a dishonest specification.

>> document.readyState is not reliable.
>
> Since some browsers don't have it at all, I have to use
> window.onload as a fallback anyway.
>

^

The implementation of document.onreadystatechange is not boolean. The
point the callback fires is unspecified and implementations vary.

Really, I'd just go with window.onload. Another approach to consider is
adding the script to the bottom and just invoking it.

<body>
<div id="toc-container">...</div>

[cms contents]

<script type="text/javascript">fillToc();</script>
</body>
</html>

Aside from that, looking at your code, you did not terminate a few
assignment statements with semicolon. An assignment value of
functionExpression is no different:-
window.onload = function(){ };

Hans-Georg Michna

unread,
Jan 3, 2010, 6:32:45 AM1/3/10
to
On Fri, 01 Jan 2010 15:36:22 -0800, Garrett Smith wrote:

>Hans-Georg Michna wrote:

>>> The example code, the callback for document.onreadystatechange changes
>>> context from document to window.

>> Oops, didn't even notice. What's the simplest way to do it
>> better? How do you even know what the original context was?

>When the function's internal [[Call]] property is invoked, if the `this`

>value is not an object (null is not an object), then the `this` value is
>the global object. Saving the value of document.onreaystatechange in an
>identifier, the identifier gets the functional value. When the call
>operator is used on that identifier, the base object is null and so the
>this value is the global object.
>
>var oldReadyHandler = document.onreadystatechange;

Thanks a lot for the excellent explanations!

So would it solve this inaccuracy to save the handler
temporarily in the document object, rather than in a variable,
such as:

document.onreadystatechangeOld = document.onreadystatechange;

Then later, when it is no longer needed, use:

delete document.onreadystatechangeOld;

By the way, null is an object, unlike undefined, which is not an
object. Perhaps the original designer of JavaScript had a hiccup
when he wrote this. (:-)

Still null is not very suitable, so �this� perhaps defaults to
the global object in case of null.

>Really, I'd just go with window.onload.

Done. Looks much cleaner and simpler too.

>Another approach to consider is adding the script to the bottom
>and just invoking it.

Yes, thought about that, but it gives the web designer who uses
the script another opportunity to do something wrong.

Also, in a Content Management System the script user may only be
able to get to the bottom of his content, not to the ultimate
bottom of the page code, which may cause problems in some cases.

So I'll stick to window.onload and hope that the DOM
specification designers one day see the light and give us what
we really need.

>Aside from that, looking at your code, you did not terminate a few
>assignment statements with semicolon. An assignment value of
>functionExpression is no different:-
>window.onload = function(){ };

Oops, that slipped through the cracks! Fixed. Thanks for finding
this!

Hans-Georg

David Mark

unread,
Jan 3, 2010, 9:58:17 AM1/3/10
to
On Jan 3, 6:32 am, Hans-Georg Michna <hans-

georgNoEmailPle...@michna.com> wrote:
> On Fri, 01 Jan 2010 15:36:22 -0800, Garrett Smith wrote:
> >Hans-Georg Michna wrote:
> >>> The example code, the callback for document.onreadystatechange changes
> >>> context from document to window.
> >> Oops, didn't even notice. What's the simplest way to do it
> >> better? How do you even know what the original context was?
> >When the function's internal [[Call]] property is invoked, if the `this`
> >value is not an object (null is not an object), then the `this` value is
> >the global object. Saving the value of document.onreaystatechange in an
> >identifier, the identifier gets the functional value. When the call
> >operator is used on that identifier, the base object is null and so the
> >this value is the global object.
>
> >var oldReadyHandler = document.onreadystatechange;
>
> Thanks a lot for the excellent explanations!
>
> So would it solve this inaccuracy to save the handler
> temporarily in the document object, rather than in a variable,
> such as:
>
> document.onreadystatechangeOld = document.onreadystatechange;

No. That solves nothing and could create big problems. Try it in IE
after this:-

document.expando = false;

You never augment host objects.

>
> Then later, when it is no longer needed, use:
>
> delete document.onreadystatechangeOld;

Nor do you attempt to delete their properties.

>
> By the way, null is an object,

The null value is not an object, regardless of what its typeof result
might seem to indicate.

> unlike undefined, which is not an
> object.
> Perhaps the original designer of JavaScript had a hiccup
> when he wrote this. (:-)

Perhaps. The typeof result seems pretty idiotic (look at the
confusion it causes). :)

>
> Still null is not very suitable, so »this« perhaps defaults to
> the global object in case of null.

As described in the specs.

>
> >Really, I'd just go with window.onload.
>
> Done. Looks much cleaner and simpler too.

Just remember that you are stepping on the onload attribute of the
body.

>
> >Another approach to consider is adding the script to the bottom
> >and just invoking it.
>
> Yes, thought about that, but it gives the web designer who uses
> the script another opportunity to do something wrong.

I've heard the "our users are idiots" argument ad nauseam, even from
frameworks that ostensibly target programmers. Now, for Web
developers, I can see it, but the DOM ready trick should be an
optional second script. It's no more complicated to paste one script
in the head and an optional second script at the end. Hell, call the
second putatendofbody.js.

>
> Also, in a Content Management System the script user may only be
> able to get to the bottom of his content, not to the ultimate
> bottom of the page code, which may cause problems in some cases.

No question there.

Garrett Smith

unread,
Jan 4, 2010, 1:27:11 AM1/4/10
to
Hans-Georg Michna wrote:
> On Fri, 01 Jan 2010 15:36:22 -0800, Garrett Smith wrote:
>
>> Hans-Georg Michna wrote:
>
>>>> The example code, the callback for document.onreadystatechange changes
>>>> context from document to window.
>
>>> Oops, didn't even notice. What's the simplest way to do it
>>> better? How do you even know what the original context was?
>
>> When the function's internal [[Call]] property is invoked, if the `this`
>> value is not an object (null is not an object), then the `this` value is
>> the global object. Saving the value of document.onreaystatechange in an
>> identifier, the identifier gets the functional value. When the call
>> operator is used on that identifier, the base object is null and so the
>> this value is the global object.
>>
>> var oldReadyHandler = document.onreadystatechange;
>
> Thanks a lot for the excellent explanations!
>

Sure. I also suggest reading the specification for "Function Calls" in
ECMA-262 r3.

You can read an unofficial online edition:-
http://bclary.com/2004/11/07/#a-11.2.3

Also for Function Code:
http://bclary.com/2004/11/07/#a-10.2.3

That is neither a normative reference nor a disgusting PDF format.

> So would it solve this inaccuracy to save the handler
> temporarily in the document object, rather than in a variable,
> such as:
>
> document.onreadystatechangeOld = document.onreadystatechange;

No, not an expando.

>
> Then later, when it is no longer needed, use:
>
> delete document.onreadystatechangeOld;
>

Definitely not that. Calling delete on a Host object in IE will usually
throw an error.

I would use Function.prototype.call instead.

function readyStateChangeHandler(ev) {
ev = ev || window.event;
if(oldready) {
oldready.call(this, ev);
}
}

The callback can use

function theOriginalReadyHandler(ev){
if(this.readyState == "complete") alert("complete");
}

and it should work as expected.

> By the way, null is an object, unlike undefined, which is not an
> object. Perhaps the original designer of JavaScript had a hiccup
> when he wrote this. (:-)
>

No, null is not an object; null is a primitive value.

Notice that the table for the `typeof` operator has special handling for
`null`. There was another thread not too long ago with VK, I think
kangax' review for "Professional JavaScript" that explained about null.

> Still null is not very suitable, so �this� perhaps defaults to
> the global object in case of null.
>

That's what happens in function calls in ES3.

[...]

>
>> Another approach to consider is adding the script to the bottom
>> and just invoking it.
>
> Yes, thought about that, but it gives the web designer who uses
> the script another opportunity to do something wrong.
>
> Also, in a Content Management System the script user may only be
> able to get to the bottom of his content, not to the ultimate
> bottom of the page code, which may cause problems in some cases.
>

It may cause problems when requiring the elements to be rendered
completely (measuring offsetWidth, or style values).

> So I'll stick to window.onload and hope that the DOM
> specification designers one day see the light and give us what
> we really need.
>

HTML 5 specifies DOMContentLoaded. There isn't a good way to detect if
the browser will fire that event (or other DOM events).

The un-detectible "activation" and "domfocusin" event proposals had the
same predicament and died for the same reasons.

Garrett Smith

unread,
Jan 4, 2010, 2:24:58 PM1/4/10
to
David Mark wrote:
> On Jan 3, 6:32 am, Hans-Georg Michna <hans-
> georgNoEmailPle...@michna.com> wrote:
>> On Fri, 01 Jan 2010 15:36:22 -0800, Garrett Smith wrote:
>>> Hans-Georg Michna wrote:
>>>>> The example code, the callback for document.onreadystatechange changes
>>>>> context from document to window.
>>>> Oops, didn't even notice. What's the simplest way to do it
>>>> better? How do you even know what the original context was?
>>> When the function's internal [[Call]] property is invoked, if the `this`
>>> value is not an object (null is not an object), then the `this` value is
>>> the global object. Saving the value of document.onreaystatechange in an
>>> identifier, the identifier gets the functional value. When the call
>>> operator is used on that identifier, the base object is null and so the
>>> this value is the global object.
>>> var oldReadyHandler = document.onreadystatechange;
>> Thanks a lot for the excellent explanations!
>>
>> So would it solve this inaccuracy to save the handler
>> temporarily in the document object, rather than in a variable,
>> such as:
>>
>> document.onreadystatechangeOld = document.onreadystatechange;
>
> No. That solves nothing and could create big problems. Try it in IE
> after this:-
>
> document.expando = false;

Is there any good reason to set document.expando = false?

If you do that the `unselectable` property won't work.

>
> You never augment host objects.
>

Augmenting host objects is error prone.

scrollBy.x = 1; // IE Error.

[...]

Also for DOM objects that have DOM readonly. This might seem to map to
ECMAScript ReadOnly but you shouldn't expect that. Assignment to a DOM
readonly property must be disallowed whether or not an exception is
thrown depends on the language.

In ES5 Strict mode, assigning to a property where [[Writable]] is false
or assigning to a property with a getter but no setter, will result in
TypeError. Assinging to an undeclared identifier will too.

Implementations are known to use a getter for DOM readonly.

When trying to set a property with a getter and no setter, the result is
an Error. Here is an example:-

document.onclick = function(ev){
// Try to modify DOM readonly clientX
// http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-MouseEvent
ev.clientX = 10;
};

Run that, then lick the document in Firefox and see:

| "Error: setting a property that has only a getter"

John G Harris

unread,
Jan 4, 2010, 3:06:37 PM1/4/10
to
On Sun, 3 Jan 2010 at 22:27:11, in comp.lang.javascript, Garrett Smith
wrote:
>Hans-Georg Michna wrote:

<snip>


>> By the way, null is an object, unlike undefined, which is not an
>> object. Perhaps the original designer of JavaScript had a hiccup
>> when he wrote this. (:-)
>>
>
>No, null is not an object; null is a primitive value.

<snip>

That's true now, but there are signs that it was different in the far
distant past. It looks as though it was originally thought of as an
object pointer that happens to have a null value, as in Java, C++, etc.

As a result some ancient parts of javascript still call it an object,
and they are too ancient to be changed. Possibly it's sometimes
implemented as an object pointer with a null value, but this is not
visible from outside.

John
--
John Harris

Lasse Reichstein Nielsen

unread,
Jan 4, 2010, 4:00:47 PM1/4/10
to
John G Harris <jo...@nospam.demon.co.uk> writes:

> On Sun, 3 Jan 2010 at 22:27:11, in comp.lang.javascript, Garrett Smith
> wrote:
>>Hans-Georg Michna wrote:

>>No, null is not an object; null is a primitive value.
> <snip>
>
> That's true now, but there are signs that it was different in the far
> distant past. It looks as though it was originally thought of as an
> object pointer that happens to have a null value, as in Java, C++, etc.

Now you are guessing.

Anyway, in Java, null is not an object either. It's an Object
Reference value, referring to no object, and there is a different null
value of each object type.

In JavaScript, you don't have type requirements, so you just need one
null value, and it's still not an object - so it's a primitive value.

Whether it's really necessary to have both null and undefined (and
not, e.g., just two names for the same value) is a different
discussion.
I guess that the idea was to allow people to write something that
looked like Java. :)

> As a result some ancient parts of javascript still call it an object,
> and they are too ancient to be changed. Possibly it's sometimes
> implemented as an object pointer with a null value, but this is not
> visible from outside.

Indeed. And it's a royal pain the the backside that (typeof o ==
"object") doesn't guarantee that it's actually an object.

/L
--
Lasse Reichstein Holst Nielsen
'Javascript frameworks is a disruptive technology'

Hans-Georg Michna

unread,
Jan 4, 2010, 4:25:17 PM1/4/10
to
On Sun, 03 Jan 2010 22:27:11 -0800, Garrett Smith wrote:

>function readyStateChangeHandler(ev) {
> ev = ev || window.event;
> if(oldready) {
> oldready.call(this, ev);
> }
>}

Thanks, but now I'm getting confused with the execution
contexts. How does this relate to my code? Since I'm no longer
using document.readyState, only window.onload, my code currently
looks like this:

// Keep preexisting handler and append own handler:
var precedingOLHandler = window.onload;

window.onload = function () {
// Remove all handlers:
window.onload = null;
// Execute all handlers exactly once:
if (precedingOLHandler) precedingOLHandler();
doTheActualWork();
}

I remove all handlers after the event fired to suppress any
repeat firing that some crazy browser might try. Thought it
can't hurt.

While we're at it, what's the likelihood of missing the
window.onload event? What if some sloppily designed browser
fires the event while putting off the JavaScript processing or
for some reason forgets to fire it at all? Can we rely on such
things never happening?

Hans-Georg

Hans-Georg Michna

unread,
Jan 4, 2010, 4:25:17 PM1/4/10
to
On Sun, 3 Jan 2010 06:58:17 -0800 (PST), David Mark wrote:

>On Jan 3, 6:32�am, Hans-Georg Michna <hans-
>georgNoEmailPle...@michna.com> wrote:

>> On Fri, 01 Jan 2010 15:36:22 -0800, Garrett Smith wrote:

>> >Hans-Georg Michna wrote:

>> >>> The example code, the callback for document.onreadystatechange changes
>> >>> context from document to window.

>> >> Oops, didn't even notice. What's the simplest way to do it
>> >> better? How do you even know what the original context was?

[Detailed explanations why another option does not work snipped]

So what am I to do? I guess the context change does not matter,
as there is no good reason for the onload event handler to make
itself dependent on "this". Mine certainly doesn't.

Please see my next message for the simplified code I now use.

Hans-Georg

Garrett Smith

unread,
Jan 4, 2010, 5:42:44 PM1/4/10
to
Hans-Georg Michna wrote:
> On Sun, 03 Jan 2010 22:27:11 -0800, Garrett Smith wrote:
>
>> function readyStateChangeHandler(ev) {
>> ev = ev || window.event;
>> if(oldready) {
>> oldready.call(this, ev);
>> }
>> }
>
> Thanks, but now I'm getting confused with the execution
> contexts.

When the browser calls `readyStateChangeHandler`, what is the `this` value?

What do Function.prototype.call/apply do with the first argument?

How does this relate to my code? Since I'm no longer
> using document.readyState, only window.onload, my code currently
> looks like this:
>
> // Keep preexisting handler and append own handler:
> var precedingOLHandler = window.onload;
> window.onload = function () {
> // Remove all handlers:
> window.onload = null;
> // Execute all handlers exactly once:
> if (precedingOLHandler) precedingOLHandler();
> doTheActualWork();
> }
>

What is the base object for the function call `precedingOLHandler()`?

What is the execution context when precedingOLHandler is called?

(in ES3; ES5 in strict mode is another matter).

> I remove all handlers after the event fired to suppress any
> repeat firing that some crazy browser might try. Thought it
> can't hurt.
>

The other event handlers were already removed. Setting onload to null
there means the callback won't fire again. For example, if a load event
is synthesized and dispatched to window using createEvent/initMouseEvent.

> While we're at it, what's the likelihood of missing the
> window.onload event? What if some sloppily designed browser
> fires the event while putting off the JavaScript processing or
> for some reason forgets to fire it at all? Can we rely on such
> things never happening?
>

window.onload is reliable where js enabled in the browser.

Garrett Smith

unread,
Jan 4, 2010, 7:14:57 PM1/4/10
to
Lasse Reichstein Nielsen wrote:
> John G Harris <jo...@nospam.demon.co.uk> writes:
>
>> On Sun, 3 Jan 2010 at 22:27:11, in comp.lang.javascript, Garrett Smith
>> wrote:
>>> Hans-Georg Michna wrote:
>
>>> No, null is not an object; null is a primitive value.
>> <snip>
>>
>> That's true now, but there are signs that it was different in the far
>> distant past. It looks as though it was originally thought of as an
>> object pointer that happens to have a null value, as in Java, C++, etc.
>
> Now you are guessing.
>
> Anyway, in Java, null is not an object either. It's an Object
> Reference value, referring to no object, and there is a different null
> value of each object type.
>
> In JavaScript, you don't have type requirements, so you just need one
> null value, and it's still not an object - so it's a primitive value.
>
> Whether it's really necessary to have both null and undefined (and
> not, e.g., just two names for the same value) is a different
> discussion.
> I guess that the idea was to allow people to write something that
> looked like Java. :)
>

Either that or to provide some sort of mapping from Java null to
something other than undefined.

s = new java.util.Vector(1);
s.setSize(10);
s.elementAt(0);

Expected result would be null.

(that example will run in a java enabled browser; runs in Firebug)

David Mark

unread,
Jan 4, 2010, 7:17:57 PM1/4/10
to
On Jan 4, 4:25 pm, Hans-Georg Michna <hans-

georgNoEmailPle...@michna.com> wrote:
> On Sun, 3 Jan 2010 06:58:17 -0800 (PST), David Mark wrote:
> >On Jan 3, 6:32 am, Hans-Georg Michna <hans-
> >georgNoEmailPle...@michna.com> wrote:
> >> On Fri, 01 Jan 2010 15:36:22 -0800, Garrett Smith wrote:
> >> >Hans-Georg Michna wrote:
> >> >>> The example code, the callback for document.onreadystatechange changes
> >> >>> context from document to window.
> >> >> Oops, didn't even notice. What's the simplest way to do it
> >> >> better? How do you even know what the original context was?
>
> [Detailed explanations why another option does not work snipped]
>
> So what am I to do? I guess the context change does not matter,
> as there is no good reason for the onload event handler to make
> itself dependent on "this". Mine certainly doesn't.

Exactly. It shouldn't be an issue.

John G Harris

unread,
Jan 5, 2010, 3:14:09 PM1/5/10
to
On Mon, 4 Jan 2010 at 22:00:47, in comp.lang.javascript, Lasse
Reichstein Nielsen wrote:
>John G Harris <jo...@nospam.demon.co.uk> writes:
>
>> On Sun, 3 Jan 2010 at 22:27:11, in comp.lang.javascript, Garrett Smith
>> wrote:
>>>Hans-Georg Michna wrote:
>
>>>No, null is not an object; null is a primitive value.
>> <snip>
>>
>> That's true now, but there are signs that it was different in the far
>> distant past. It looks as though it was originally thought of as an
>> object pointer that happens to have a null value, as in Java, C++, etc.
>
>Now you are guessing.

Obviously. That's why I wrote 'It looks as though' ... .


>Anyway, in Java, null is not an object either. It's an Object
>Reference value, referring to no object, and there is a different null
>value of each object type.
>
>In JavaScript, you don't have type requirements, so you just need one
>null value, and it's still not an object - so it's a primitive value.

That's why I wrote 'object pointer', alias pointer to object. An Object
Pointer type can be defined to include a null value, or not, whichever
is thought more desirable. Since ECMA 262 was put together it's been
not.

The fact that the language doesn't allow you to handle pointers directly
may have influenced the final choice.


>Whether it's really necessary to have both null and undefined (and
>not, e.g., just two names for the same value) is a different
>discussion.

This is part of the evidence for suspecting that null was originally
thought of as the null member of a pointer type.


>I guess that the idea was to allow people to write something that
>looked like Java. :)

I suspect not.


>> As a result some ancient parts of javascript still call it an object,
>> and they are too ancient to be changed. Possibly it's sometimes
>> implemented as an object pointer with a null value, but this is not
>> visible from outside.
>
>Indeed. And it's a royal pain the the backside that (typeof o ==
>"object") doesn't guarantee that it's actually an object.

This is the other part of the evidence.

John
--
John Harris

Hans-Georg Michna

unread,
Jan 10, 2010, 11:53:49 AM1/10/10
to
On Mon, 04 Jan 2010 14:42:44 -0800, Garrett Smith wrote:

>Hans-Georg Michna wrote:

>> While we're at it, what's the likelihood of missing the
>> window.onload event? What if some sloppily designed browser
>> fires the event while putting off the JavaScript processing or
>> for some reason forgets to fire it at all? Can we rely on such
>> things never happening?

>window.onload is reliable where js enabled in the browser.

Thanks, good to know.

Hans-Georg

0 new messages