controljs
controljs copied to clipboard
Scripts with missing or near-term cache-control headers requested twice
Originally discussed <a
href=http://groups.google.com/group/controljs/browse_thread/thread/aa4f4885827c1
d31/61e1387b3a1e20fd#61e1387b3a1e20fd>on this thread</a>.
What steps will reproduce the problem?
1. Load a script using ControlJS which delivers a no-cache cache-control header
value. An example would be any ad server
2. You can configure Fiddler's AutoResponder to send no-cache headers.
What is the expected output? What do you see instead?
ControlJS uses an Image or Object element to pre-fetch the URL, but has to
create an actual Script element to execute it. When the URL cannot be cached,
it will be re-requested.
In the attached screenshot, Multiples.jpg, Fiddler was configured with an
auto-responder to send a Cache-control: no-cache header. You can see how
jQuery is requested twice.
The spec is evolving so ControlJS' pre-fetching behavior will be supported
natively (discussed <a
href=http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order>here</a> ).
Until that time, this ccan be fixed in Internet Explorer using the
readystatechange event.
IE will download any resource as soon as its SRC attribute is set and update
its readyState property to "loaded" once the resource has been downloaded;
however, script element will **not execute** until it is inserted into the DOM.
This is analogous to how all browsers implement dynamically created images:
the image is fetched when the src attribute is set, but is not displayed until
the element is added to the DOM.
ControlJS can use this to replace its current pre-fetching mechanism in IE and
eliminate the possibility scripts will be requested multiple times.
Please provide any additional information below.
The attached patch implements this in ControlJS. Instead of using an IMG to
pre-fetch, it creates an actual script element. Once the script's readyState
property moves to "loaded", the code stores the actual script element in the
CJS.hLoaded object. This is done in the CJS.downloadScriptPrefetch method.
In the CJS.execScript, a check is added to see if the value for
CJS.hLoaded[src] is a SCRIPT element. It then inserts this script element into
the DOM instead of creating a new one. This prevents double-retrieval of
un-cacheable URLs and still maintains the on-demand execution pattern.
The screenshot Singular.jpg shows the effect of this patch.
Original issue reported on code.google.com by [email protected]
on 17 Dec 2010 at 1:09
Attachments:
It might be esp. valuable to do this for IE.
In menu.php the two scripts (jquery.min.js and fg.menu.js) get loaded twice -
first as images and then as scripts. The intention is that the 2nd pass (as
scripts) would be read from cache. But when I run the example multiple times
one or both of the scripts frequently get re-requested and generate a 200
response - so they're downloaded twice.
I believe this is due to quirky caching behavior in IE - if you have a Vary
header and no ETag then IE is flaky about caching. In this case those scripts
have a Vary header and no ETag (or at least a blank ETag).
Therefore, it's more likely that the current technique (load as image then load
as script) will cause double downloads in IE. If instead we move to this new
approach where the file is only requested once, the issue is avoided.
Original comment by [email protected]
on 17 Dec 2010 at 1:29
It should be noted that this will work only in IE -- the other browsers either
do not begin to download the script until it's inserted (Opera) or don't
provide the readystatechange event.
IMO, this seems to be an elegant means by which dynamic scripts can be managed.
The recommendation of a noted wpo expert to the w3c to include readystate
notification in the HTML 5 specification would carry considerable weight.
Original comment by [email protected]
on 17 Dec 2010 at 6:08
Attached patch contains two fixes: 1) undefined variables in non-IE browsers
and 2) resolution to the problem of aborted connections due to premature GC.
Demonstration of #2: http://digital-fulcrum.com/webperf/ieabort/fail/
Original comment by [email protected]
on 23 Dec 2010 at 8:05
Attachments:
Step 12 in the HTML5 specification
(http://www.w3.org/TR/html5/scripting-1.html#running-a-script) suggests the
following:
"For performance reasons, user agents may start fetching the script as soon as
the attribute is set, instead, in the hope that the element will be inserted
into the document."
In Browsers that implement this suggestion (currently only IE) pre-fetching can
be accomplished simply by creating the script and assigning its src attribute
-- when execution is desired, the script can be inserted into the document.
This patch waits until the script element transitions to the "loaded" state
before it will be inserted and is overly complex and relies on a non-standard
property and event.
It probably makes more sense to use the specification's suggestion as the
*core* of the pre-fetching. I personally believe we should make the
non-conforming browser vendors aware of this suggestion in the spec. Should
they choose NOT to implement it, does it make sense for ControlJS to
consciously *subvert* their decision?
Original comment by [email protected]
on 27 Dec 2010 at 7:09