Closed Bug 226416 Opened 21 years ago Closed 21 years ago

No way to detect when document loaded with window.open finishes loading

Categories

(Core :: DOM: Core & HTML, defect, P1)

defect

Tracking

()

RESOLVED FIXED
mozilla1.6beta

People

(Reporter: hubert.kauker, Assigned: bzbarsky)

References

()

Details

Attachments

(2 files)

User-Agent:       Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6a) Gecko/20031030
Build Identifier: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6a) Gecko/20031030

When a document is loaded into a new (or existing) frame or window it should be
expected, that a script doing this has a way to discover when that document has
been fully loaded and all its objects are available for use.

Apparently, neither the document property of the new window, nor document.body,
nor document.body.innerHTML all together are capable to do this.

By the way: in Internet Explorer one can use the condition
document.readyState == "complete"
to check on analogous situations.

It is very hard, however, to produce a test case.

So I use a document with a "very long" body containing a script which assigns a
long string to a variable.
I load this document at the same time into two new windows and monitor the
loading progress.
When document, document.body, and document.body.innerHTML seem to indicated that
all is finished, I try to read the 'data' variable from each window, which is
set by the new document.
In most cases I get an 'undefined' value.

Using simpler documents, however, succeeds.

But Mozilla should be a little more deterministic, shouldn't it?



Reproducible: Sometimes

Steps to Reproduce:
1. Load http://www.travelbasys.de/kauker/test/CheckReadyState.html
2.
3.

Actual Results:  
Most of the time, the 'data' variable defined in one of the new windows has an
'undefined' value.

Expected Results:  
The 'data' variable should be defined.
> that a script doing this has a way to discover when that document has
> been fully loaded and all its objects are available for use.

Yeah. It's called "the onload event handler".  Use that, please.

> When document, document.body, and document.body.innerHTML seem to indicated
> that all is finished

None of those indicate anything.  Why would you think that they do?
Status: UNCONFIRMED → RESOLVED
Closed: 21 years ago
Resolution: --- → INVALID
Sorry, you misunderstood.
I know fully well the intention and usage of the window.onload() event handler.
It is usually set INSIDE the document being loaded to handle the respective 
event in its 'host' window.

But the problem is: how can a window, say 'A', find out when a document in 
ANOTHER window, say 'B' has been fully loaded and all its objects are usable?

Could you please fill me in with this tiny bit of detail?
If there is no way of window 'A' getting to know this, may be the bug should
be reopened.
I naturally assumed that when 'A' finds that document.body of 'B' is valid, 
then all objects which in some way 'depend' on it are valid as well.
Thanks.
if you have control over the second window:
<body onload="window.loaded=true;"> and check if loaded is set to true in the
child window.
Granted.
When I happen to have control over window two I can do all sorts of things 
there including set up my own onload handler there which tells window one about 
the end of the job.

But what when I can NOT persuade window two to cooperate? When I do not 'own' 
it?

The idea is: 

When I have script code inside a SCRIPT element, nested inside a BODY element, 
nested inside a HTML element, I sort of assume that an 'inner' element becomes 
valid before an 'outer' element.
By becoming 'valid' I mean that the thing can used as specified.
So when document.body becomes valid, a SCRIPT element inside it should have 
become valid before, which means that all script code inside it has been 
successfully parsed and executed, which means that a variable which is a 
property of the window object, after all, can be used by any external method.

By the same token, a SCRIPT element inside the HEAD of a document, should be 
valid as soon as document.getElementsByTagName("script") returns the SCRIPT 
element in its return array.



> I sort of assume that an 'inner' element becomes valid before an 'outer'
> element.

Bad assumption...

> So when document.body becomes valid, a SCRIPT element inside it should have
> become valid before,

document.body becomes defined as soon as we parse the <body> open tag.  Manu
existing pages depend on this.

Note that you can do:

  w = window.open(whatever);
  w.onload = function { /* do something */ }

which involves no control over the contents of the window you are opening.
bz: that would override a possibly already existing onload handler right?
The other way around.  If the opened window sets its own onload handler, it
would override yours.
> document.body becomes defined as soon as we parse the <body> open tag.  

Can't be true. 
Maybe document.body is CREATED when the body tag is parsed.
But it certainly will not be appended to its parent node until the end body is 
parsed.
At that time, however, both the script and the end script tags will have been 
parsed and appended to its parent node, too.
So the question is: when are the assignment statements contained in the script 
executed? Is that possibly in a parallel thread which would need more careful 
synchronization?
> w = window.open(whatever);
> w.onload = function { /* do something */ }

> cb: that would override a possibly already existing onload handler right?

> bz: The other way around.  
> bz: If the opened window sets its own onload handler, it would override yours.

The first case would break the new page.
The second case would make the trick useless.
So let's forget it.

> But it certainly will not be appended to its parent node until the end body is
> parsed.

Ah, but it will.  That's the only way incremental rendering of web pages can
work.  All nodes get appended to the parents as soon as the start tag is parsed;
that way if the interrupt timer fires partway through parsing of a node, we can
incrementally show whatever we've got up to that point.

> when are the assignment statements contained in the script executed?

For an inline script?  Right after the </script> is parsed.

> Is that possibly in a parallel thread which would need more careful
> synchronization?

Not in Mozilla, but yes in some other browsers, iirc (eg Opera).

In any case, this bug, as filed, is still invalid.  None of the methods you were
trying are indicative of anything regarding whether the load of the page is done.
> None of the methods you were trying are indicative of anything regarding 
whether the load of the page is done.

But please: what *IS* indicative whether the load of the page is done?
I do need this for my web application?
I know that in IE, I can use an interval timer timer and periodically check 
whether the condition "document.readyState == 'complete'" has become true.
What can I do in Mozilla?
Use:
   w.addEventListener('load', function() { /* do something */ }, false);
Thank you, Ian. That's very kind.
I suppose you mean

var w = window.open( url, ... );
w.addEventListener('load', function() { /* do something */ }, false);

Right?

But since window.open() is not guaranteed to be a synchronous operation,
you'll be running into serious timing problems here.
You simply do not know, when addEventListener() will be executed.
Is the new document already loaded then or is it not?

In any case I made a test page:
http://www.travelbasys.de/kauker/test/readystateworkaround.html

and it does NOT work. Try yourself.
Hrm. That _should_ work, no? bz?
Yes, that should work, iirc.
bz: Well it does't...

Hubert: Could you file a bug on this?
Ian: yes, I noticed.  That's why I cced danm and jst.  I'd like to hear what
they say, since they're most familiar with this neck of the woods...
IIRC, the problem is that when a window is opened, we load about:blank
(synchronously, IIRC), and then when the actual document comes in off the
network, we clear event handlers (as we're supposed to) and start over. This
special case needs to be taken into account here, but it's not...
Yup. The w.addEventListener('load',...) in your example is attached to the bogus
preliminary document after it has finished loading. Then the load event listener
is cleared out just before the real contents are loaded, so it never fires.

This means, and I just tried this, that you can get what you want with an unload
listener. Yeah, that's pretty messed up.
Hmm...  so what do we want to do?  Do we want to clear all listeners except
onload listeners?  Or do we want to leave all listeners when going from
about:blank to a page with the same principal as the opener (like we currently
do with the JS scope)?
Reopening and resummarizing to reflect the real issue.
Status: RESOLVED → UNCONFIRMED
Resolution: INVALID → ---
Summary: The document, document.body, and document.body.innerHTML properties do not indicate reliably when a document is fully loaded and all its objects are available to scripting. → No way to detect when document loaded with window.open finishes loading
Or maybe just not clear event listeners on the window at all when leaving
about:blank, i.e. tie that code into the code that does JS_ClearScope()...
Status: UNCONFIRMED → NEW
Ever confirmed: true
Right.  Should it be subject to all the same conditions (non-chrome document,
same security principal, leaving about:blank)?  Or just "don't clear if leaving
about:blank"?
IMO it should be subject to all the same conditions.
Attached patch Like this?Splinter Review
Attachment #136275 - Flags: superreview?(jst)
Attachment #136275 - Flags: review?(danm-moz)
Comment on attachment 136275 [details] [diff] [review]
Like this?

Yeah, looks good.
Attachment #136275 - Flags: superreview?(jst) → superreview+
I just filed a bug (226703) as suggested by Hixie in comment #16.
See http://bugzilla.mozilla.org/show_bug.cgi?id=226703.

May I draw your attentation to another thread
http://bugzilla.mozilla.org/show_bug.cgi?id=226432

Here the question "what should be reset when a new document is loaded"
is already under discussion.
Depends on: 226703
*** Bug 226703 has been marked as a duplicate of this bug. ***
Comment on attachment 136275 [details] [diff] [review]
Like this?

Looks good to me. Note this is an improvement but we're still not quite there.
It would be better if event listeners on the temporary about:blank bogodocument
were deaf. We still get an anomalous unload event while loading a window's
first document (comment 19).

Note of possible historical interest: we didn't RemoveAllListeners for any
about:blank document for a very long time until rev 1.449 (Oct 2001) for bug
18553. This patch would seem to be a better version of that one.
Attachment #136275 - Flags: review?(danm-moz) → review+
Comment on attachment 136275 [details] [diff] [review]
Like this?

Could this please be approved for 1.6b?
Attachment #136275 - Flags: approval1.6b?
It was too much fun to write not to post. Though it doesn't add much that we
didn't already know. Note it behaves much better with the patch applied, but
the unload is of course still there.

(The festival of focus events has already been noted; that's bug 164686.)
Does this allow one site to determine how long it takes another site to load, or
are there cross-site scripting checks in the patch?
There are cross-site scripting checks in the patch.
Comment on attachment 136275 [details] [diff] [review]
Like this?

a=asa (on behalf of drivers) for checkin to 1.6beta
Attachment #136275 - Flags: approval1.6b? → approval1.6b+
Assignee: general → bz-vacation
OS: Windows 2000 → All
Priority: -- → P1
Hardware: PC → All
Target Milestone: --- → mozilla1.6beta
*** Bug 134335 has been marked as a duplicate of this bug. ***
Fixed for 1.6b.
Status: NEW → RESOLVED
Closed: 21 years ago21 years ago
Resolution: --- → FIXED
Just out of interest, does this patch actually solve the problem the reporter 
was asking about, or does detecting document loads still involve a race 
condition?

From comment 13:
1: var w = window.open( url, ... );
/* start loading */
/* finish loading */
2: w.addEventListener('load', function() { /* do something */ }, false);

If the document completes loading after line 1, but before line 2 has had a 
chance to add the event listener, will the event listener fire?

Or are we suggesting that since the document load takes /such/ a long time to 
(asynchronously) complete - relative to the time that window.open takes to 
return - that there's virtually no chance that the load could complete before 
line 2 has finished executing?
All loads (except for the initial load of about:blank) are asynchonous and
essentially happen on the main thread (the same thread that the JS is running
on), so there is no possibility of a race there, unless the two lines of code
run off of different timers, or cause mozilla to spin a sub-event loop (by
performing synchronous IO, or opening modal dialogues).
So the JS execution actually blocks the load? If I do:

var w = window.open( url, ... );
really_slow_function();

Will the window not commence loading until really_slow_function returns?
If the function just runs and doesn't put up any modal dialogs or make any
disk/network I/O requests, yes.
(The anomalous unload event (comment 19, comment 29) is bug 197709).
I missed all the fun.

The use of a blank bogo-document seems to be the root of much evil.  Why is that
necessary?  It wasn't in the ancient (Nav2 and on) daze, when I made sure (a)
you could preset onload after window.open, which by definition is asynch; and
(b) no bogo-doc was loaded synchronously, to generate spurious unload or other
events.

/be
about:blank bogodocument's raison d'etre is the subject of new bug 227028.
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: