Skip to main content

Bug Tracker

Side navigation

#12282 closed bug (fixed)

Opened August 13, 2012 01:12PM UTC

Closed August 20, 2012 12:20PM UTC

Last modified October 15, 2012 08:03PM UTC

1.8.0 regression - document ready is fired too early on IE 9/10

Reported by: vrodic@gmail.com Owned by: mikesherov
Priority: high Milestone: 1.8.1
Component: core Version: 1.8.0
Keywords: Cc:
Blocked by: Blocking:
Description

Hi,

We have a weird banner system that injects an external script with document.write that triggers a regression in $(document).ready() in jQuery 1.8.0 (jQuery 1.7.2 works fine).

Basically, document ready is fired before the object defined below document ready code section is called (on IE 9 or IE10 - IE 10 is from last years Windows 8 developer preview).

I've created a minimal test case at:

http://www.centarnekretnina.net/dev/test.html

The page should execute alert("test");

IE10 dev tools console outputs:

SCRIPT5007: Unable to get value of the property 'init': object is null or undefined

test.html, line 20 character 5

You can download the two small files (test.html and test2.js), change the jquery version and see that this works fine on jQuery 1.7.2

Attachments (0)
Change History (31)

Changed August 13, 2012 01:18PM UTC by rwaldron comment:1

owner: → vrodic@gmail.com
status: newpending

Thanks for taking the time to contribute to the jQuery project! Please provide a complete reduced test case on jsFiddle to help us assess your ticket.

Additionally, be sure to test against the jQuery Edge version to ensure the issue still exists. To get you started, use this boilerplate:  http://jsfiddle.net/FrKyN/ Open the link and click to "Fork" (in the top menu) to get started.

Changed August 13, 2012 01:38PM UTC by anonymous comment:2

I can't reliably reproduce it with jsfiddle (it probably introduces more side-effects), and my version is pretty minimal already.

I've created another version:

http://www.centarnekretnina.net/dev/test3.html

That uses http://code.jquery.com/jquery-git.js (jQuery edge)

You may have to reload the page for the error (no "test" alert) to occur.

Changed August 13, 2012 01:44PM UTC by vrodic@gmail.com comment:3

status: pendingnew

Actually I've found a way to reproduce it on jsfiddle (testing on Windows 8 dev preview - IE10)

http://jsfiddle.net/dKDdj/2/

After it loads once, click jsfiddle "Run" to run again and take a look at IE10 console (open it before you click run)

Changed August 13, 2012 05:59PM UTC by mikesherov comment:4

component: unfiledcore
milestone: None1.8.1
owner: vrodic@gmail.commikesherov
priority: undecidedhigh
status: newassigned

Changed August 13, 2012 09:57PM UTC by anonymous comment:5

Here is an update that reproduces it without any external resources beyond jQuery.

http://jsfiddle.net/dKDdj/4/

Changed August 13, 2012 10:34PM UTC by mikesherov comment:6

This is great, thanks.

Changed August 15, 2012 02:47PM UTC by Denis comment:7

Confirmed in IE9 too.

Changed August 16, 2012 11:25AM UTC by SoonDead comment:8

_comment0: Confirmed in may application too. \ \ $(document).ready() fires before all the javascript files are loaded in IE9.1345116342282811

Confirmed in my application too.

$(document).ready() fires before all the javascript files are loaded in IE9.

Changed August 16, 2012 04:05PM UTC by mikesherov comment:9

Rather than more "me too", it would be helpful if you guys posted examples and links to see this in action.

Changed August 16, 2012 05:07PM UTC by mikesherov comment:10

keywords: → needsdocs

So, this fiddle: http://jsfiddle.net/dKDdj/4/ does not exhibit a problem with .ready(). .ready() is a deferred http://api.jquery.com/category/deferred-object/ .

If the DOM is ready when you call it, it will execute synchronously.

If the DOM is not ready when you call it, it will execute asynchronously.

In the example provided, you are relying on the async execution of .ready(), which isn't a gaurantee. This is because .ready() fires a bit earlier in 1.8 because it does a new check for DOM readiness.

If someone has proof that the DOM can't be manipulated on .ready(), I'd love to hear about it.

SoonDead, Denis, do you have examples?

needs docs to re-emphasis the promisey nature of .ready()

Changed August 16, 2012 09:08PM UTC by markoj21@gmail.com comment:11

Here is the issue in jsFiddle thank you vrodic, we were having this issue when we just updated to 1.8

Using the mvc3, with partials this problem presents it self in many areas. It works correctly with IE7 and IE8, Chrome and Firefox.

When you first access the js fiddle link it will run correctly, press the run button it will break. if you change to jquery 1.7.2 it runs correctly it both scenarios.

http://jsfiddle.net/tgo16/H6zte/4/

Test machine IE9 9.0.8112.16421, Windows 7 SP1

Changed August 16, 2012 09:18PM UTC by mikesherov comment:12

markoj21, please read what I wrote. Of course it will break, as you're assuming something about .ready() that just isn't true. It isn't gauranteed to execute asynchronously.

Changed August 17, 2012 09:46AM UTC by anonymous comment:13

So, it seems that in many cases (WebKit, Gecko, IE < 9) ready() currently fires asynchronously but in IE9 it does not. I get that there is no guarantee, but it is likely that many people have been making this incorrect assumption and so the change in detection logic is exposing it and causing breakage. This is going to be a headache to fix...

Changed August 17, 2012 10:02AM UTC by jaubourg comment:14

I don't see how it is a headache. It's as simple as moving the call to $.ready at the end of the inline script. Where it should have been in the first place.

It's not so much that ready is asynchronous in other browsers but rather that the document is actually ready when executing the inline script in IE9. IE9 is better at detecting DOM readiness than other browsers here, seeing as, if the inline script is being executed, it means it was parsed thus so was the whole document.

Anyway, since the dom is ready, the handler is called immediately. The real problem is that our documentation doesn't emphasize the fact a handler will be called immediately if the DOM is ready, even though it's been the case since DOM readiness was first introduced in jQuery.

Changed August 17, 2012 02:47PM UTC by ChrisS comment:15

I've another situation where $(document).ready() is fired too early.

I've a JSP with a default page buffer of 8kb. Which means if the buffer is full it will be flushed and the browser gets the content generated until this time.

Lets assume a client has submitted a search request and the search will take a few seconds. In case the page buffer is full, for example the header and the navigation was generated, it will be flushed to the client, before the server side search is done and has generated any content. In my case the client has already received some script blocks with a $(document).ready() call. But the javascript the $(document).ready() call should execute is at the end of the page. And due to the server side search, which takes a while, the page isn't completely generated yet.

Now the Problem is that IE9 sometimes fires $(document).ready() even if the page isn't complete generated.

Below is a little JSP example which demonstrates this issue. I would expect to see "PAGE END" in the console at first. But sometimes I see "document ready" in the console at first.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
   <head> 
		<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
		<title>Test</title>
		<script type="text/javascript" src="/js/jquery-core/1.8/jquery-1.8.min.js"></script>
	</head>
	<body>
		<h1>TEST</h1>
		
		<script type="text/javascript">
		$(document).ready(function() {
			console.log("document ready");
		});
		</script>

		<%
			// Force the buffer to flush (default is 8kb)
			for (int i = 0; i < (8 * 1024); i++) {
				out.write(" ");
			}
		%>
	
		<h2>Sleeping 1 second (simulating server side process)</h2>
		<%	
			try {
				Thread.sleep(1000);
			} catch(Exception e) {
			}
		%>

		<h2>ready</h2>
		<p><a href="?">click</a></p>

		<script type="text/javascript">
			console.log("PAGE END");
		</script>
		
	</body>
</html>

Changed August 17, 2012 02:52PM UTC by dmethvin comment:16

@ChrisS, are the results consistent if there is some HTML below the "PAGE END" log, or if the JavaScript in that block does a document.write? Just curious about the conditions that might affect it.

Changed August 17, 2012 03:11PM UTC by jaubourg comment:17

If that's the case, it could be the nail in the coffin of readyState === "interactive" :/

Changed August 17, 2012 03:14PM UTC by jaubourg comment:18

BTW, isn't that what longLoad.php in test/data/event is supposed to test for?

Changed August 17, 2012 03:17PM UTC by jaubourg comment:19

Could explain this: http://swarm.jquery.org/result/154890 though I have no clue why it wouldn't fail before.

Changed August 17, 2012 05:22PM UTC by cdowns comment:20

I've had issues when a page has an .ready in the header that calls something from a script block in the body. It looks similar to an issue that requireJS had (https://github.com/requirejs/domReady/commit/a3e0dd8b6d3d3ee636ff0ca6a5a7c302d6ab33bf). The issue when debugging in IE9 seems to show up due to line 835 of core.js (changed in f5fd41252e3ae48a655c5da4a0b2910bb897b6ed):

if ( document.readyState === "complete" || ( document.readyState !== "loading" && document.addEventListener ) )

IE9 at that point is readyState === "interactive" so it goes through with the .ready, but then you get to line 379 of the .ready:

// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
		if ( !document.body ) {
			return setTimeout( jQuery.ready, 1 );
		}

IE9 will give back a document.body that hasn't run all the scripts. Would it be better at that section to actually do the same .addEventListener stuff that is in the ready.promise instead of just calling the ready again until document.body exists? So for the case that document.body doesn't exist, couldn't you rely on the DOMContentLoaded firing like you do in the ready promise?

Changed August 17, 2012 06:28PM UTC by mikesherov comment:21

@cdowns, the problem here seems to be that document.body exists, and readyState === "interactive", but DOM clearly isn't ready. I think we can fix this by changing the location in which we do Diego Perini's famous doScroll check. We'll see.

@jaubourg, it's not what longLoad.php is doing. That is a long loading iframe on a page to keep interactive going even though DOM is ready. This test case would be partial page load triggers interactive too early when DOM clearly isn't ready.

Hopefully, I can repro this. Silly IE.

Changed August 17, 2012 06:33PM UTC by dmethvin comment:22

_comment0: @mikesherov, maybe @cdowns has something there. If we could detect whether the browser supports `DOMContentModified` we could just ignore `.readyState` entirely, which would cover IE9 and IE10. Unfortunately, the trick we already use in support.js runs afoul of Content Security policy so we can't do it that way.1345228625809851

@mikesherov, maybe @cdowns has something there. If we could detect whether the browser supports DOMContentLoaded we could just ignore .readyState entirely, which would cover IE9 and IE10. Unfortunately, the trick we already use in support.js runs afoul of Content Security policy so we can't do it that way.

Changed August 17, 2012 10:05PM UTC by anonymous comment:23

@ChrisS @SoonDead @vrodic @mikesherov @jaubourg

I have the same problem :

(jQuery 1.8.0) - IE9 sometimes fires $(document).ready() even if the page isn't complete generated.

works fine on jQuery 1.7.2

Changed August 19, 2012 09:42PM UTC by mikesherov comment:24

https://github.com/jquery/jquery/pull/901

ChrisS and cdowns, thank you thank you thank you.

Changed August 20, 2012 12:20PM UTC by Mike Sherov comment:25

resolution: → fixed
status: assignedclosed

Fix #12282. IE has premature .readyState == "interactive". Close gh-901.

Changeset: 0f553ed0ca0c50c5f66377e9f2c6314f822e8f25

Changed August 21, 2012 05:44AM UTC by ChrisS comment:26

I can confirm that the bug is fixed, now. The current version from github works fine in my test and production scenario.

Thank you, mikesherov.

Changed August 23, 2012 06:02PM UTC by michaeldobbins1@gmail.com comment:27

I also confirmed this behavior in IE9. It doesn't seem to matter whether you are in IE8 compatibility mode or 'edge' (eg. <meta http-equiv="X-UA-Compatible" content="IE=8,chrome=1,requiresActiveX=true" />). I noticed that ie9 was inconsistent in finding all of the items in a collection on $(document).ready; I added an alert right after my $(document).ready call and found that the alert would popup before all of the DOM was rendered. I upgraded to the github jquery source (1.8.1pre) and all is good; $(document).ready doesn't fire until the DOM is fully loaded. Thanks for getting this fixed - just can't wait for the official release of 1.8.1. There are several other issues with ie9 and jQuery 1.8, which I am hoping will be resolved in the upcoming release.

Changed August 25, 2012 07:19PM UTC by lucas@lucasmaia.com comment:28

Please, I can't see the solution. I have the same problem with IE9. Can I help me?

Changed August 25, 2012 07:31PM UTC by anonymous comment:29

Please, put the file to download. Thanks

Replying to [comment:26 ChrisS]:

I can confirm that the bug is fixed, now. The current version from github works fine in my test and production scenario. Thank you, mikesherov.

Changed October 03, 2012 07:31PM UTC by tentonaxe comment:30

_comment0: Was it intended for this fix to cause IE7 and IE8 to fire document.ready later than modern browsers? http://jsfiddle.net/Camilo/PFWmS/ it now seems to wait until onload.1349293019684942

Was it intended for this fix to cause IE7 and IE8 to fire document.ready later than modern browsers? http://jsfiddle.net/Camilo/PFWmS/ it now seems to wait until onload.

Edit: I guess it has always been that way.

Changed October 15, 2012 08:03PM UTC by mikesherov comment:31

keywords: needsdocs