Be in Charge of Browser Cacheing!
Browsers are supposed to obey. When you tell them not to cache content, they’re supposed to not cache content. Right? But sometimes they have a will of their own, especially when your content includes files that are external to the HTML document, such as SWFs. For example, you might have built a nifty Flash intro that your client simply adores. Everyone’s happy — but don’t pour the champagne just yet! The client’s logo has changed, so would you revise the intro? Why yes, you would. And you do, because you provide good service. You upload the new SWF, but (sigh …) your client doesn’t see the update.
Now, you can advise your client to “clear your cache,” but one person’s “sure, no problem” is another person’s “huh?” So, where does that leave you? You can walk through a How To, which might be painless, but might not. Or you can head this issue off at the pass. Let’s look at a quick solution.
Query String Approach
Browsers need to be convinced that content is new in order to initiate a new download. It would be ideal if a file’s timestamp would suffice, but in the real world, it often simply doesn’t. So, here’s an old “trick” I learned years ago. If you append a query string to your SWF reference in the HTML, and supply a throw-away variable that you change at will, you can let the browser know when to head again to the server, rather than its own cache.
If you use the default code supplied by Flash or Dreamweaver to embed a SWF, you will have both an <object> element and an <embed> element in your HTML. The <object> element will contain nested <param> elements, each of which represent properties of your SWF. One of these will look like this …
<param name="movie" value="yourMovieHere.swf" />
… and one of the <embed> element’s attributes will match this property, like this …
<embed src="yourMovieHere.swf" [other attributes here] />
To append a query string, add a question mark and an arbitrary variable name after the .swf and before the closing quotation mark.
<param name="movie" value="yourMovieHere.swf?ver" />
<embed src="yourMovieHere.swf?ver" />
Call it what you like, but I usually use “ver,” short for “version.” Now decide on a value to give this variable. Remember, this is a “dummy” variable that won’t be used for any purpose other than to nudge the browser into requesting a new file. Personally, I use a three digit number, since it isn’t likely I’ll ever get higher than 999 versions of a SWF (I sure hope not!).
<param name="movie" value="yourMovieHere.swf?ver=001" />
<embed src="yourMovieHere.swf?ver=001" />
And that does it. If your client’s logo changes, amend your FLA, recompile your SWF, change that ?ver=001 to ?ver=002 in the HTML, then upload the HTML and the SWF.
But what if I’m already using a query string?
Good question. If so, just add your throwaway variable anywhere in the mix. If you already have, for example …
?city=Virginia%20Beach&state=Virginia
… then tack yours on the end (or anywhere), delimited by an ampersand …
?city=Virginia%20Beach&state=Virginia&ver=001
Works for ActionScript, Too
This same approach can be used in your ActionScript when loading external content via loadMovie(), MovieClip.loadMovie(), the MovieClipLoader class, Sound.loadSound(), and the like. Wherever the code requires that you specify a path to the external file, simply add your query string. This works for JPGs, SWFs, MP3s, you name it.
container.loadMovie("yourMovieHere.swf?ver=001");
If You Never Want to Cache …
If, for some reason, you never want to cache, you’ll need to provide a new number every time. Manually incrementing that ver variable won’t be enough. In both ActionScript and JavaScript, you can use a combination of Math.floor() and Math.random() to accomplish this requirement. Remember, though, this means your users’ browsers will always request a new file from the server, even if it hasn’t changed.
container.loadMovie(
"yourMovieHere.swf?ver=" + Math.floor(Math.random() * 999)
);
The number 999 is arbitrary, here. It just means you’ll get a number anywhere between zero and 999, which happens to follow the numbering format used above.
In JavaScript, it gets a bit more complicated, because you have to use something like document.write() to produce the necessary <param> and <embed> elements. But it’s do-able. If enough interest in generated, I’ll drum up an example of this, too.
May 16th, 2006 at 11:06 am
I vote for an example of the Javascript implimentation for a unilateral anti-cache mechanism.
Give peace a chance!
June 1st, 2006 at 7:41 am
I put the random value for the mp3 file when the player movie is first loaded and not everytime someone presses the play button.
It worked for me. Thanks!.
June 1st, 2006 at 10:02 am
Vinod,
Good approach! In that way, you could load a fresh copy once, but not every time. I’m not sure, though, if non-query–stringed content would count as the same file as the query-stringed content. In a case like this, I might store the random number in a variable and then use the same randomly generated number as my query with each button press.
June 29th, 2006 at 11:56 am
Hi - Great tip on caching. My situation is that I’m using a lot of SWFs containing FLVs but only one HTML file. The master.swf is embedded into the HTML. Then the other elements get loaded in. If I use this technique on that one HTML will the caching “cascade” to all the SWFs?
Thanks.
Josh
June 29th, 2006 at 8:16 pm
Josh,
Actually, no — you’ll have to use it with each reference to an external file. Even with the above trick in place, every file is still downloaded to the user’s cache. It’s just that the query string causes the Flash Player (and the browser) to think it doesn’t yet have the file.
March 16th, 2007 at 5:14 am
David,
I think you’ve just saved my life, I thought I was going mad.
My problem is with the home.htm calling an SWF which is in-turn provided with ‘news’ text from an XML file. I found that the home page text would only update if I manually refreshed the XML file ‘through’ my IE7 browser.
Do I need to add the query string to both the htm ANDthe flash ….
xml.load(”stoppress.xml?ver=001″);
Obviously, the XML file is updated anyway with today’s news, so I assume that I don’t need anything extra in there?
Regards
dave
March 16th, 2007 at 6:46 pm
dave,
Both the XML file and the SWF get cached, so if your SWF uses this trick to fool the browser into requesting a new XML file, it would in theory only fool the browser once. If you changed your ActionScript to
ver=002, the older SWF (the one with the older ActionScript —ver=001) may just be the one still in use by the user. So when you update the ActionScript, I think you’ll need to update the SWF as well. I didn’t really address that in the article, but it’s a good point.March 23rd, 2007 at 5:08 pm
I too am all for a Javascript implimentation for a unilateral anti-cache mechanism. My main concern is a pre created swf file calling a xml file. Though my swf is not loading external content. Therefore, a javascript function would be most useful.
April 2nd, 2007 at 11:06 am
Similar problems with loading an FLV — if the stream breaks for whatever reason and it gets interrupted, it’ll play whatever has been cached, forever, and not try to retrieve new FLV data. I think this is more of a Flash problem than a browser problem.
If you use something like “http://example.com/file.flv?123456″, while that URL does parse correctly and the FLVPlayback object does indeed retrieve the data from file.flv via HTTP, it will sit there, loading forever (reporting bytesLoaded as -1), displaying nothing.
If that happens, try appending “.flv” to the end of your random dummy string, like “/file.flv?123456.flv”. I guess it interprets the data coming from that URL correctly as FLV data and plays it.
April 2nd, 2007 at 2:27 pm
To Jeremy (and Rich, from a way-back-when comment) …
It looks like an easy “unilateral anti-cache mechanism” for JavaScript is afforded with Geoff Stearns’ SWFObject. Search the term
addVariableand you’ll see a way to pass in variables to the JavaScript SWF embedder. In Geoff’s example …… you could use JavaScript right in any of those variables:
To steveo …
I haven’t run across the issue you’ve described, but I can see where that might be a problem. I do notice that you’re appending a number, but not a name/value pair. To match the approach suggested in the article, you might try
http://example.com/file.flv?ver=123456, whereveris just a throw-away variable short for “version.”May 8th, 2007 at 7:46 am
I actually tried to add the string to my action script but it doesn’t work?!?!
original Script
_root.textLoader.loadMovie(”textAll.swf”);
Script with String
_root.textLoader.loadMovie(”textAll.swf?ver=001″);
whet am I missing?
May 8th, 2007 at 7:50 am
Actually IT WORKED
It doesn’t work when you publish on local computer.
Thanks
May 8th, 2007 at 9:50 pm
DewDan,
Woo hoo!
May 31st, 2007 at 6:56 pm
The query string method seems to break ExternalInterface callbacks, at least on IE6 and Firefox on Windows.
June 24th, 2007 at 7:49 pm
Adam,
Thanks for the note! I haven’t done any experimentation yet to confirm, but if your observation is true, it’s a terrific “gotcha” to hold on to.
June 25th, 2007 at 12:07 pm
i’m working on a flash document that is has only 1 frame. motion is tween class generated and the images are loaded thru the loader component from folder. everything runs fine..like its supposed to.. except for in IE6/7, when i refresh, it goes to the first static frame(which in no way resembles what it is supposed to be) and.. stops.. doesn’t play….. since there is no timeline animation at all…
if i close that application.. re-open.. it works fine.. for one time.. but repeats the same thing…
works fine in firefox/safari etc…
can you give me some codes for the “If you never want to cache…” part… where in the embed and param… a new random value loads everytime…
June 27th, 2007 at 10:49 pm
suBi,
To add a random number to the HTML itself, you’ll need to use JavaScript. The least complicated way I can think of is to use an approach that already uses JavaScript to embed the SWF, such as Geoff Stearns’ SWFObject. Scroll up just a bit and see my reply to Jeremy and Rich (April 2, 2007) and you’ll see an example.
August 28th, 2007 at 7:05 pm
Any idea how to be in charge of caching included ‘.as’ files? I’m developing a file now, have cache set to 0Kb. The query string trick won’t work (malformed include error). My movie has 2 text blocks named ‘foo’ and ‘bar’.
My code in frame 1 (of 1) is:
> #include “test.as”
> bar.text = ‘working’;
test.as code is:
> foo.text = ‘bar’;
I run the movie and get ‘bar’ and ‘working’. Great. I change test.as to:
> foo.text = ‘bar2′;
and I still get ‘bar’ and ‘working’. No amount of cache clearing or restarting will clear it up.
I think it’d make a great blog post if you can solve it. The Google, she does nothing.
–Shawn
August 29th, 2007 at 6:41 am
Shawn,
I think you’re asking how to keep ActionScript (.as) files from cacheing, but that’s not what AS files do — in fact, they shouldn’t be on the server at all. The
#includedirective in ActionScript is significantly different from the concept of includes in PHP or ASP. In the latter, include files percolate to the pages that call them as soon as they’re uploaded. In ActionScript, code is compiled, or “baked,” into the SWF at compile time, at which point it becomes immutable.I’ve seen many developers update the contents of an AS file, then upload that AS file to the server, hoping the SWF will look to the update and behave differently, but
#includeonly works at compile time. It literally copies/pastes the AS file’s content into the FLA as if you had typed it there by hand … only as the SWF is generated. If you want to pull in data at runtime, you’ll have to read the contents of a text file that stores name/value pairs in the same format as a query string, or read the contents of an XML file, or hit a database, etc.Does that make sense?
September 13th, 2007 at 12:16 am
The problem with this method as others have stated, is it doesn’t work when using it on your local devbox. As far as I can tell, in AS you can’t have any kind of compiler directive to switch off this when running locally. Any suggestions on managing running locally vs. running on the web?
September 13th, 2007 at 7:45 am
JBlaze,
A compiler directive would be really nice for something like this, but the API provides a quick way to determine what mode you’re in. See the
System.capabilitiesclass, which has a staticplayerTypeproperty. Anifstatement is all you need:Of course, that doesn’t provide a way to cause the hack to work locally, but it sounds like you’re just looking for a way to turn it on or off depending on the circumstances. (The funny thing is, I haven’t noticed the technique to fail locally, but I don’t currently run a server on my local machines.)
October 17th, 2007 at 11:56 pm
Is it possible to cache a part of an flv. Thus, I wanted to precache 10% of an flv so that when I actually begin to play an FLV it will automatically load in 10 % of the flv from the browser.
I have been trying with inconsitent results…
any ideas?
October 18th, 2007 at 8:09 am
Will,
That isn’t something I’ve definitively tried to nail down. Thinking back over my own experiences — happenstance, where I would partially download a video and recompile, because I was testing something else — I, too, would say I’ve had inconsistent results. In my own endeavors, the default buffer time is usually adequate; the minor pause before the video starts has been fine.
If you goal is to avoid the pause, I believe your best bet is true streaming, by way of Flash Media Server, Red5, and the like.
Wish I had a handy answer for you!
December 13th, 2007 at 10:36 am
Is it possible to have a random number generated here instead?
December 13th, 2007 at 10:39 am
like so? Maybe the coding will show up this time…I hope
( param name=”movie” value=”yourMovieHere.swf?rand=[random number]” )
( embed src=”yourMovieHere.swf?rand=[random number]” )
December 13th, 2007 at 1:40 pm
Jdaze,
Yes, you could certainly put your random number into the HTML, but then you’d have to use JavaScript to produce that random number, which means you’d also have to use JavaScript to write out that part of the HTML. You could use the JavaScript
document.write()method or DOM scripting to do that, or — since it’s a good idea to use something like SWFObject anyway — just use your JS-based Active Content workaround of choice to introduce the random number at that point (see my reply to Jeremy and Rich on April 2, 2007).