Skip to main content

Bug Tracker

Side navigation

#13051 closed bug (wontfix)

Opened December 13, 2012 04:32PM UTC

Closed April 02, 2013 08:38PM UTC

Double script loading when present in an HTML page called in AJAX (IE < 10)

Reported by: vvo Owned by: vvo
Priority: low Milestone: None
Component: ajax Version: 1.8.3
Keywords: Cc:
Blocked by: Blocking:
Description

jQuery version: 1.8.3

browsers: IE < 10

I have set up a test page: http://jsbin.com/itovoz/1

It is a simple page including jQuery 1.8.3 that makes an AJAX call to another jsbin.com page.

In this AJAX called page I included a <script> tag, this <script> will be loaded twice by all IE < 10.

What's expected:

jquery.cookie.min.js is downloaded and executed once

What's happening:

jquery.cookie.min.js is downloaded twice

I noticed I could not ALWAYS reproduce it, I have set up tests page in webpagetest to confirm the behavior, you'll see it's loaded twice:

IE7: http://www.webpagetest.org/result/121213_S7_5b2f160556db35d8b71345f84706eb37/1/details/

IE8: http://www.webpagetest.org/result/121213_GF_3df9e063700cc48adcbdf2e602aedfa6/1/details/

IE9:

http://www.webpagetest.org/result/121213_7B_fba12e3b23d9ef5be765693a048a813c/1/details/

Could not reproduce on IE10.

As I said, sometimes everything is fine which is strange, example on IE8:

http://www.webpagetest.org/result/121213_4Z_36b3072c31b505e77694f8b0a379d656/1/details/

This is a BIG performance regression and is affecting a lot of websites.

Very hard to notice but as a webperformance consultant I have seen it many times lately on multiple clients.

jQuery 1.4.4 is not affected.

test page: http://jsbin.com/idasoh/1

test result: http://www.webpagetest.org/result/121213_FV_400864dd640776b3624b48a940b4978d/1/details/ (ran multiple times)

jQuery 1.6.2 is affected

test page: http://jsbin.com/ivicav/1

test result: http://www.webpagetest.org/result/121213_NS_87f1194933b718ddbc4901c156638178/1/details/

Attachments (0)
Change History (9)

Changed December 13, 2012 04:51PM UTC by vvo comment:1

Also, I could not find the documentation part that talk about the weird (but needed I guess) ?51651321 added to every <script> inserted in AJAX.

Changed December 13, 2012 04:55PM UTC by dmethvin comment:2

_comment0: Sorry, I can't repro on your jsbin test case with IE9. http://i.imgur.com/EhJOv.png \ \ Can you try with the current code and see if the problem is still there for you? http://code.jquery.com/jquery-git.js \ \ In general, it's **not a good idea** to design pages load scripts this way. Use `$.getScript()` or use a script loader rather than injecting HTML that happens to have script tags.1355417795539197
owner: → vvo
status: newpending

Sorry, I can't repro on your jsbin test case with IE9. http://i.imgur.com/EhJOv.png

Can you try with the current code and see if the problem is still there for you? http://code.jquery.com/jquery-git.js

In general, it's **not a good idea** to design pages that load scripts this way. Use $.getScript() or use a script loader rather than injecting HTML that happens to have script tags.

Changed December 13, 2012 05:41PM UTC by vvo comment:3

_comment0: Thanks for answering so fast. \ \ All I can say is that you should try harder. \ As I said and prove (see WPT links for IE8 working well sometimes), this is not happening everytime so this must be based on a timer or something. \ \ Here's another catch using HTTPWatch on IE9, http://i.imgur.com/e4IHa.png \ And using IE9 developper tools http://i.imm.io/OZpq.png \ \ Yes its not a good idea but this is a regression since it should work as the docs says: \ \ "html": Returns HTML as plain text; included script tags are evaluated when inserted in the DOM. \ \ from http://api.jquery.com/jQuery.ajax/ \ \ Using jQuery.load this way is perfectly fine, I mean I never stumbled accross a "jQuery best practice" saying that we should not do that. \ \ The docs of jQuery.ajax even says that if there's a <script> in it it will work fine since it will be evaluating it so why not doing it? (I'm trying to find justification why some people are doing it) \ \ Yes this is a bad practice but a lot of people are doing this in production.1355420709578136
status: pendingnew

Thanks for answering so fast.

First, using latest jquery as you provided does not solves it: http://www.webpagetest.org/result/121213_4J_60683a5c9b7256e109b54801a1b9390a/1/details/.

Second,

All I can say is that you should try harder (sorry really).

As I said and prove (see WPT links for IE8 working well sometimes), this is not happening everytime so this must be based on a timer or something.

Here's another catch using HTTPWatch on IE9, http://i.imgur.com/e4IHa.png

And using IE9 developper tools http://i.imm.io/OZpq.png

Yes its not a good idea but this is a regression since it should work as the docs says:

"html": Returns HTML as plain text; included script tags are evaluated when inserted in the DOM.

from http://api.jquery.com/jQuery.ajax/

Using jQuery.load this way is perfectly fine, I mean I never stumbled accross a "jQuery best practice" saying that we should not do that.

The docs of jQuery.ajax even says that if there's a <script> in it it will work fine since it will be evaluating it so why not doing it? (I'm trying to find justification why some people are doing it)

Yes this is a bad practice but a lot of people are doing this in production.

Changed December 13, 2012 06:01PM UTC by dmethvin comment:4

status: newopen
All I can say is that you should try harder (sorry really).

I can see that it occurred from the webpagetest traces. I can mark this open but since I can't repro it the ticket will probably not get any action. If you can repro it consistently you could trace through jQuery and see where the problem is occurring.

Changed December 13, 2012 06:01PM UTC by dmethvin comment:5

component: unfiledajax
priority: undecidedlow

Changed December 13, 2012 06:03PM UTC by vvo comment:6

Replying to [comment:4 dmethvin]:

> All I can say is that you should try harder (sorry really). I can see that it occurred from the webpagetest traces. I can mark this open but since I can't repro it the ticket will probably not get any action. If you can repro it consistently you could trace through jQuery and see where the problem is occurring.

I'll try to do that yes. It seems very strange that you could NEVER reproduce it even after many reloads (and cache busting) ?

Changed January 06, 2013 08:39PM UTC by dmethvin comment:7

@vvo, still waiting on further analysis from you. I tried doing some debugging but the test case is using the compressed jquery and when I tried switching it to the uncompressed version on the jQuery CDN I was getting errors from jsbin.

As far as *why* it's requested twice, you can see the reason in the webpagetest.org traces:

http://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.2/jquery.cookie.min.js
http://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.2/jquery.cookie.min.js?_=1355420580018

Since the two requested URLs have different query strings the browser doesn't use the previously requested version.

Changed January 21, 2013 06:56PM UTC by vvo comment:8

_comment0: Hello, so I did a lot of digging. \ \ First you'll find a jquery fork with an simple example to reproduce the bug here: https://github.com/vvo/jquery/tree/double_script_bug. \ \ Here I copy paste my commit log: \ What I have found: \ \ The double script bug is easily reproductible. \ - Clear your browser cache \ - Use any network observer \ - cd jquery, launch http-server . -p 80 (npm install http-server) \ - browse with IE9 and network observer to http://ip:80 \ - see double script loading. One for script.js, other for \ script.js?timestamp \ \ The javascript is not executed two times, only once. \ \ But still it is loaded twice! \ \ I used "blind man debugging" (putting returns and reloading the page \ untill no more script/only one scrip loads) \ \ I tracked down the first javascript load (script.js) to be done by: \ src/manipulation.js#284: \ fragment = jQuery.buildFragment( args, this[ 0 \ ].ownerDocument, false, this ); \ \ This function will create a new dom fragment element using the ajax \ request response text. If you return; just before this call, of course \ your page will fail but you'll see that there's no more script loaded. \ \ Then if you return just after, you'll see that there's the script.js \ loaded. \ \ The second load of scirpt.js?timestamp is done by the append function: \ manipulation.js#111 \ this.appendChild( elem ); \ \ So, creating a fragment with a <script src> in it will download the \ script once, then appending will download the script again (with a \ timestamp added, the timestamp is not a problem, this is the standard \ jQuery procedure of loading <scripts> in ajax calls) \ \ What we should do I guess is replace() just before creating the fragment \ to pre-add the timestamp to the script. \ \ As I just discovered jQuery core, I need some advice here. \ \ [[Image(http://dl.dropbox.com/u/3508235/7IE9%20test%20%5BRunning%5D%20-%20Oracle%20VM%20VirtualBox_006.png)]]1358794715218243

Hello, so I did a lot of digging.

First you'll find a jquery fork with an simple example to reproduce the bug here: https://github.com/vvo/jquery/tree/double_script_bug.

Here I copy paste my commit log:

What I have found:

The double script bug is easily reproductible.

  • Clear your browser cache
  • Use any network observer
  • cd jquery, launch http-server . -p 80 (npm install http-server)
  • browse with IE9 and network observer to http://ip:80
  • see double script loading. One for script.js, other for

script.js?timestamp

The javascript is not executed two times, only once.

But still it is loaded twice!

I used "blind man debugging" (putting returns and reloading the page

untill no more script/only one script loads)

I tracked down the first javascript load (script.js) to be done by:

https://github.com/vvo/jquery/blob/double_script_bug/src/manipulation.js#L284:

fragment = jQuery.buildFragment( args, this[ 0

].ownerDocument, false, this );

This function will create a new dom fragment element using the ajax

request response text. If you return; just before this call, of course

your page will fail but you'll see that there's no more script loaded.

Then if you return just after, you'll see that there's the script.js

loaded.

The second load of scirpt.js?timestamp is done by the append function:

https://github.com/vvo/jquery/blob/double_script_bug/src/manipulation.js#L111

this.appendChild( elem );

So, creating a fragment with a <script src> in it will download the

script once, then appending will download the script again (with a

timestamp added, the timestamp is not a problem, this is the standard

jQuery procedure of loading <scripts> in ajax calls)

What we should do I guess is replace() just before creating the fragment

to pre-add the timestamp to the script.

As I just discovered jQuery core, I need some advice here.

[[Image(http://dl.dropbox.com/u/3508235/7IE9%20test%20%5BRunning%5D%20-%20Oracle%20VM%20VirtualBox_006.png)]]

Changed April 02, 2013 08:38PM UTC by markelog comment:9

resolution: → wontfix
status: openclosed

In IE, script loading starts right after script element became a DOM-node, execution however, happens only after it's attached to the document – http://jsfiddle.net/YR5ar/, that's what happens in

jQuery.buildFragment
, fixing that, would require manipulation of the argument string, which seems as overkill for that case.