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 comment:1
Changed December 13, 2012 04:55PM UTC by 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: | new → pending |
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 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: | pending → new |
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 comment:4
status: | new → open |
---|
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 comment:5
component: | unfiled → ajax |
---|---|
priority: | undecided → low |
Changed December 13, 2012 06:03PM UTC by 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 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 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 comment:9
resolution: | → wontfix |
---|---|
status: | open → closed |
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.
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.