GreenSock


PreloadAssetManager - An Intelligent Preloading Queue

Posted in Preloading by jack on the July 13th, 2007


Version 2.93, Updated 3/31/2008

  • Compatibility: Flash Player 6 and later (ActionScript 2.0) (FLV preloading requires Flash Player 7)
  • File Size added to published SWF: About 3Kb

Download Now
 
Donate

Join Club GreenSock to get updates and a lot more

DESCRIPTION

Provides an easy way to invisibly preload SWFs, FLVs, or images and optionally trigger a callback function when preloading has finished. It also provides _width and _height information for all successfully preloaded SWFs or images, and duration information for FLVs (assuming they were encoded properly and have MetaData). By default, it will initially only load enough of each asset to determine the size (bytes) of each asset so that it can accurately report the percentLoaded_num, getBytesLoaded() and getBytesTotal(), then it loops back through from the beginning and finishes all the preloading. If you're not going to use a preloader status bar that polls these methods/properties, you can just set the trackProgress_boolean property to false to skip that initial delay.

OBJECTIVES

  • Provide an easy way to sequentially preload assets.
  • Determine and retain the _width and _height of any preloaded SWFs or image assets as well as the duration of any FLV assets.
  • For easy status reporting, provide percentLoaded_num, getBytesLoaded() and getBytesTotal() information for the entire group of assets in any PreloadAssetManager instance.
  • Allow for any asset to be prioritized in the loading queue at any time (for example, if the user clicks on something that requires an asset that hasn't loaded yet).
  • Allow the entire queue to be paused and resumed at any time (if, for example, you need to perform some other bandwidth-intensive action)
  • Build in the ability to call any function when either a particular asset has finished preloading or when a group of assets have finished preloading and allow the developer to pass any number of arguments/parameters to that function.
  • If an asset cannot be loaded, implement a timeout procedure so things don't get hung up indefinitely.

USAGE


Constructor: new PreloadAssetManager(assetUrls_array:Array, onComplete_func:Function, onCompleteArguments_array:Array, trackProgress_boolean:Boolean);

  • Description: Constructor. If you pass in an assetUrls_array, it will automatically call the start() function and begin preloading. You can pause() if you want.
  • Arguments:
    1. assetUrls_array: [optional] An array of urls that should be preloaded
    2. onComplete_func: [optional] A reference to a function that you'd like to call as soon as all of the assets in this PreloadAssetManager instance have been preloaded.
    3. onCompleteArguments_array: [optional] An array of arguments to pass the onComplete_func function.
    4. trackProgress_boolean: [optional] true by default. If you're NOT going to use a preloader status bar that polls the precentLoaded_num, getBytesLoaded() or getBytesTotal(), set this value to false to skip that initial delay and speed things up.



addAsset(url_str:String, onComplete_func:Function, onCompleteArguments_array:Array):PreloadAsset

  • Description: Adds an asset to the PreloadAssetManager's queue.
  • Arguments:
    1. url_str: The url of the asset that needs to be preloaded
    2. onComplete_func: [optional] A reference to a function that you'd like to call as soon as this asset has been preloaded.
    3. onCompleteArguments_array: [optional] An array of argument values to pass the onComplete_func function.



addAssets(assetUrls_array:Array, onComplete_func:Function, onCompleteArguments_array:Array, start_boolean:Boolean):Array

  • Description: Adds an asset to the PreloadAssetManager's queue.
  • Arguments:
    1. assetUrls_array: An array of URLs that need to be preloaded
    2. onComplete_func: [optional] A reference to a function that you'd like to call as soon as all of the assets in this PreloadAssetManager have been preloaded.
    3. onCompleteArguments_array: [optional] An array of argument values to pass the onComplete_func function.
    4. start_boolean: [optional] false by default. If true, the PreloadAssetManager will be forced to start preloading as soon as these assets have been added.


start()

  • Description: Starts preloading the assets (same as resume() if things are paused).



resume()

  • Description: Resumes all preloading.


pause()

  • Description: Pauses preloading in ALL PreloadAssetManagers.

PreloadAssetManager.prioritize(url_str:String):PreloadAsset

  • Description: A STATIC method that allows you to prioritize a particular asset (bump it up to the top of the queue). You can also use the non-static prioritizeAsset() method or the PreloadAsset.prioritize() method to perform a similar action.
  • Arguments:
    1. url_str: The URL of the asset that should be prioritized.




PreloadAssetManager.getAsset(url_str:String):PreloadAsset

  • Description: A STATIC method that allows you to find the PreloadAsset instance with a particular URL. This is useful if you want to find the _width or _height or duration of an asset but only know the URL.
  • Arguments:
    1. url_str: The URL of the asset you'd like to find.

EXAMPLES


To preload 2 SWFs ("myFile1.swf" and "myFile2.swf") and then call a function named onFinish(), do:

  1. import gs.dataTransfer.PreloadAssetManager;
  2. var preloader_obj = new PreloadAssetManager(["myFile1.swf","myFile2.swf"], onFinish);
  3. function onFinish(pl_obj:PreloadAssetManager):Void {
  4.     trace("Finished preloading all " + pl_obj.assets_array.length + " assets!");
  5.     var a = pl_obj.assets_array;
  6.     for (var i = 0; i < a.length; i++) {
  7.         if (a[i].fileType_str == "flv") {
  8.             trace("--Asset: "+a[i].url_str+" had a duration of: "+a[i].duration);
  9.         } else {
  10.             trace("--Asset: "+a[i].url_str+" had a width of: "+a[i]._width+", and a height of "+a[i]._height);
  11.         }
  12.     }
  13. }


Or if you want to have more granular control, you can create add each one to the PreloadAssetManager and then query properties like preloaded_boolean, _width, or _height individually like:

  1. import gs.dataTransfer.PreloadAssetManager;
  2. import gs.dataTransfer.PreloadAsset;
  3. var preloader_obj = new PreloadAssetManager();
  4. var pl1_obj = preloader_obj.addAsset("myFile1.swf", onPreload);
  5. var pl2_obj = preloader_obj.addAsset("myFile2.swf", onPreload);
  6. preloader_obj.start();
  7. function onPreload(pl_obj:PreloadAsset):Void {
  8.     trace("finished preloading: "+pl_obj.url_str+", _width: "+pl_obj._width+", _height: "+pl_obj._height);
  9. }


You can query the percentLoaded_num property to find out the status at any time (very useful for building
preloader progress bars) like so:

  1. import gs.dataTransfer.PreloadAssetManager;
  2. var preloader_obj = new PreloadAssetManager(["myFile1.swf","myFile2.swf"]);
  3. this.onEnterFrame = function() {
  4.     myPreloader_mc.bar_mc._xscale = preloader_obj.percentLoaded_num;
  5.     if (preloader_obj.percentLoaded_num == 100) {
  6.         gotoAndPlay("start");
  7.     }
  8. }

Need Help?

Feel free to e-mail me a question. I'd highly recommend joining Club GreenSock to get prioritized access to my time in answering your question, and so that you receive updates and lots more. When you e-mail your question, please include a simplified FLA file (and any class files) that clearly demonstrates the problem and provide a brief explanation.

PERMISSION

PreloadAssetManager is free. You're welcome to use it for commercial purposes - I only ask that you consider joining Club GreenSock. As the classes have gained popularity, I must admit that I've been a little overwhelmed by the amount of time it has taken to answer questions and continue development. Less than 1/100th of one percent of my blog visitors donate anything, so it has been difficult justifying the time away from billable jobs (of which there's no shortage!). I really LOVE writing classes like this, and if I could do it all day everyday, I would. But without enough donations, it's just not realistic.

Author: Jack Doyle, (e-mail: jack at greensock.com)
Copyright 2007, GreenSock (This work is subject to the terms here.)


29 Responses to 'PreloadAssetManager - An Intelligent Preloading Queue'

Subscribe to comments with RSS or TrackBack to 'PreloadAssetManager - An Intelligent Preloading Queue'.

  1. laurent said,

    on February 7th, 2007 at 8:42 am

    Great Class!

    How do I resolve the scope in an onFinish function?

    coverMC = target.createEmptyMovieClip(”cover”,target.getNextHighestDepth());
    var preload_obj = new PreloadAsset(coverImage, onFinish);
    function onFinish(asset_obj:PreloadAsset):Void {
    trace(”Finished preloading: “+ asset_obj.url_str+” and its width is: “+asset_obj._width+” and its _height is: “+asset_obj._height);
    trace(this);
    // here I want to load in coverMC
    }

    how do I load the preloadAsset into coverMC when onFinish is called?

  2. jack said,

    on February 7th, 2007 at 4:53 pm

    If you want to control the scope of the onFinish call, I’d recommend using the mx.utils.Delegate class that comes with Flash. Then to load your asset into coverMC, you could use something like loadMovie() So your edited code would be:

    import mx.utils.Delegate;
    coverMC = target.createEmptyMovieClip(”cover”,target.getNextHighestDepth());
    var preload_obj = new PreloadAsset(coverImage, Delegate.create(this, onFinish));
    function onFinish(asset_obj:PreloadAsset):Void {
    trace(”Finished preloading: “+ asset_obj.url_str+” and its width is: “+asset_obj._width+” and its _height is: “+asset_obj._height);
    trace(this);
    coverMC.loadMovie(asset_obj.url_str);
    }


  3. on March 22nd, 2007 at 11:25 pm

    [...] http://blog.greensock.com/?p=7 [...]

  4. leolea said,

    on April 4th, 2007 at 9:59 am

    Preloading works super fine! Thank you very much for this class.

    I am preloading a bunch of FLVs. Once they get at 100%, how do I access them using a NetStream object (or other) ?

    (I need to implement something that initates the playback of the first one, when it reaches the end I must start the second one, so on…)

  5. jack said,

    on April 4th, 2007 at 10:41 am

    Leolea, this class simply preloads your assets into your browser’s cache; it is not meant to be used to play back and manage your FLVs once they’re preloaded. There’s nothing special that you need to do in order to access the preloaded FLVs - just call them as you normally would either using a NetStream object of your own or an FLVPlayback component or whatever. The user’s browser will be smart enough to used the cached versions instead of going out to the web and downloading them again.

  6. Giani said,

    on April 15th, 2007 at 9:16 am

    Excellent. Very useful for projects that use runtime shared assets.

    Nice job : )

  7. Gabriel said,

    on April 25th, 2007 at 11:43 am

    Hmmm. A little customization might be necessary for streaming FLV handling. An ideal FLV preloader might wait until the currently-streaming FLV is fully cached before loading an FLV in the background.

    If the user requests a new FLV, it would ideally halt the bg-downloading stream and resume it after the requested FLV was fully cached. That assumes it’s possible to halt (and resume) a stream?

    If the user requests the background-loading FLV, it’d need to be swapped into the playback area without re-starting that netstream from the beginning.

    Has anyone out there tried something like this?

  8. jack said,

    on April 25th, 2007 at 11:59 am

    Gabriel, the issues you bring up are exactly why I built this class. It’s very easy to pause preloading and resume it anytime you want (see the pause() and resume() functions) so that you can manage the user’s bandwidth efficiently. You can also prioritize any asset anytime based on what the user clicks on. So if asset #2 is currently preloading, but the user clicks on something that requires asset #6 (which hasn’t been preloaded yet), you can prioritize it immediately (see the prioritize() function).

  9. Gabriel said,

    on April 25th, 2007 at 3:11 pm

    I definately like thought of being able to prioritize, pause and resume the loading of assets.

    After a little investigating, it seems like Flash can’t resume downloading a half-cached FLV? It just starts the stream over from scratch. This can make pausing and resuming the queue a frustrating experience–if the currently-playing clip ends before the preloading clip is finished, the preloading clip is flushed and then starts loading again from the beginning.

    It’s not a flaw in your preloader, so much as it is a difficulty with FLV caching. Ideally, we should be able to pause the video stream itself (pause buffering), then resume it later (resume buffering). If we could drop the currently-preloading clip into the video object without re-starting the stream (allowing it continue buffering from where it is), but still start playing from the beginning, we’d be set.

  10. fozzo said,

    on July 17th, 2007 at 5:27 am

    I can’t get it to work, the onCompleteArguments_array!
    Can someone give an example?

  11. jack said,

    on July 17th, 2007 at 7:06 am

    fozzo,

    Your onCompleteArguments_array arguments will get passed to your onComplete_func. As an added convenience, the PreloadAssetManager or PreloadAsset instance will get appended as the last argument (depending on whether you defined the onComplete_func via the PreloadAssetManager constructor or for an individual PreloadAsset using the addAsset() method). Here’s an example:

    import gs.dataTransfer.PreloadAssetManager;
    var preloader_obj = new PreloadAssetManager(["myFile1.swf","myFile2.swf"], onFinish, ["arg1","arg2","arg3"]);
    function onFinish(arg1:String, arg2:String, arg3:String, pl_obj:PreloadAssetManager):Void {
    trace(”Finished preloading all assets! Argument 1:”+arg1+”, argument 2:”+arg2+”, argument 3:”+arg3);
    var a = pl_obj.assets_array;
    for (var i = 0; i < a.length; i++) {
    trace(”Asset: “+a[i].url_str+” had a width of: “+a[i]._width+”, a height of “+a[i]._height+”, or if it’s an FLV with MetaData, its duration is: “+a[i].duration);
    }
    }

    Hope that helps!


  12. on July 19th, 2007 at 10:31 am

    [...] I was searching for a quick way to preload multiple files but wasn’t having much luck until I found a great page listing various preloading classes that simplify most common content loading tasks. Out of all the preloading classes listed on the site, I chose GreenSock’s Preload Asset Manager class because the documentation made getting accurate getBytesTotal and getBytesLoaded results look super easy (it was) and because it had a relatively small file size. [...]


  13. on August 10th, 2007 at 5:02 pm

    Hi! This class has made my life much easier… I have a couple of questions, though:

    1. Is there a way to get the width/height of the FLV, alongside the duration?
    2. Do you anticipate adding an XML option to this class? For example, the ability to load ANY kind of file… images, xml, swfs, flvs, etc.

    Thanks, great job!

    -nick

  14. jack said,

    on August 14th, 2007 at 12:32 am

    Nicolas, I just added the ability for the width, height, videodatarate, framerate, audiodatarate, and basically all of the available meta data in an FLV to be read in when it preloads. The sample is updated too. Keep in mind that not all FLVs have this meta data available - it depends on the software you used to encode the FLV. Sorenson Squeeze seems to do a good job, but several other software packages omit most of the meta data in which case this class obviously won’t be able to grab it.

    Enjoy!

  15. Graydon said,

    on September 25th, 2007 at 10:17 pm

    Great class.

    Implemented it in a project we just did requiring preloading a number of FLVs (user has to disconnect their internet connection in the middle of a set of videos). Worked like a charm.

    Thanks.

  16. Krom said,

    on October 5th, 2007 at 4:35 pm

    Is there a way to destroy the PreloadAssetManager object or will simply deleting the var kill any preloads that may currently exist?

    Thank you!

  17. jack said,

    on October 5th, 2007 at 4:46 pm

    Krom, you can call the destroy() method on your PreloadAssetManager instance. Or if you want to pause ALL preloading that’s being handled by any/all PreloadAssetManagers, just call the static PreloadAssetManager.pauseAll() method.

  18. jack said,

    on October 29th, 2007 at 3:55 pm

    Please keep in mind that PreloadAssetManager is meant to preload assets, not buffer video. So if you have a 10 minute FLV and want to buffer 2 minutes of it before playing it, use a NetStream and its bufferTime property instead of PreloadAssetManager. My class simply leverages the browser’s cache to do its magic, but in order to work properly, it needs to fully download an asset. If you download 20% of an FLV using PreloadAssetManager and then try to play that on the screen, Flash will request the file from the browser which will in turn check its cache and since it’s not fully there, it’ll make the request from the server and start the load over again. Not ideal by any means.

  19. mark said,

    on November 7th, 2007 at 4:01 pm

    Very useful.
    Is there any way to get the percentLoaded_num of an individual asset?
    I want to build separate progress bars for each asset.

  20. jack said,

    on November 7th, 2007 at 4:26 pm

    Mark,

    You can check the progress of any asset after you’ve added it to the PreloadAssetManager. For example, to check the status of a file named “myURL.swf”, do something like:

    var asset_obj = PreloadAssetManager.getAsset(”myURL.swf”);
    var percentLoaded_num = (asset_obj.getBytesLoaded() / asset_obj.getBytesTotal()) * 100;

  21. Stephen said,

    on December 4th, 2007 at 2:53 pm

    I’m just now starting to learn some of the more advanced functions of actionscript and I’m pretty sure that I’ve got the hang of this class but I have a question that will hopefully clear some things up for me.

    Say I’ve got a movieclip that loads a random jpg from a list as a “background” so, in order to make sure that the background comes up without a hitch, I have to have all of the backgrounds loaded. My question is whether or not I should use loadMovie to get the jpg into the movieclip or some other function now that the jpg has already been preloaded. Also, should I be referring to the PreloadAssetManager’s array_asset for the src of the image now or just stick with the original url?

    I may just be missing something but, I’ll preload the backgrounds and when I go to load the image, I notice in the bandwidth profiler that the swf has requested the file again even though the file should be cached.

    Whatever help you can provide would be greatly appreciated.

  22. jack said,

    on December 4th, 2007 at 3:04 pm

    Yes, you’ve got it right, Stephen - you need to use loadMovie() (or its equivalent) to load your background images into place. PreloadAssetManager is ONLY meant to get the assets into your browser’s cache, nothing more. And that also explains why Flash’s bandwidth profiler is requesting the file again. That’s to be expected, and that’s exactly what the browser does too, but since it checks its cache FIRST before hitting the server again, it finds the asset(s) and loads them from there for much snappier performance. Again, PreloadAssetManager leverages the BROWSER’S cache but Flash’s bandwidth profiler doesn’t.

  23. Banta67 said,

    on January 3rd, 2008 at 6:03 pm

    Thank Goodness.

    Spent the whole day looking for a sollution. This one works.

    YOU ROCK!

  24. tom d said,

    on January 26th, 2008 at 11:29 am

    awesome, i was starting to implement a simple version of this and happened across yours, does everything i want and does it very well :) will be sure to let you know of the project url when it’s done! thank you for saving my time :)

  25. ekion said,

    on January 28th, 2008 at 5:30 pm

    Hi,
    I would like to know if this preloading asset exist for AS3 ?
    if it doesn’t, will u think about converting this asset for AS3 ?

    Thanks for ur time if you could answer on my email. it would be great.

  26. jack said,

    on January 30th, 2008 at 11:47 am

    I’ll probably port this to AS3 when I get a project that requires it. I’m not entirely sure when that’ll be though.

  27. Danny said,

    on March 11th, 2008 at 10:48 am

    Jack, thanks for the code. I got it to work (took a while because I’m novice and never worked with custom classes before). I’ll be spreading the good word about your blog and generous sharing. Thanks again.

  28. Juan said,

    on April 7th, 2008 at 3:45 pm

    Buddy you are a genius. This is by far the best preloader I’ve come across.

  29. oyster said,

    on May 9th, 2008 at 7:36 pm

    Hi,
    RE AS3 integration.

    I guess we can use this on a preload page to cache as3 assets.

    ie
    preload.html
    _as2 preload assets (AS3.swfs)
    _onComplete ( getURL( “next.html” )
    next.html
    _AS3 assets

    yes?
    Thanks i love this class. I train my students to use it in managing their flash frameworks.
    Oyster

Leave a Reply