我知道你正在经历什么。不幸的是,我从未见过一个好的解决方案基本上,异步代码只是以这种方式结束。
一个解决方案算法:
static var resourcesNeededAreLoaded:Boolean = false;
static var shouldDoItOnLoad:Boolean = false;
function doSomething()
{
if(resourcesNeededAreLoaded)
{
actuallyDoIt();
}
else
{
shouldDoItOnLoad = true;
loadNeededResource();
}
}
function loadNeededResource()
{
startLoadOfResource(callBackWhenResourceLoaded);
}
function callBackWhenResourceLoaded()
{
resourcesNeededAreLoaded = true;
if(shouldDoItOnLoad)
{
doSomething();
}
}
这种模式允许你做延迟加载,但你也可以在必要时强制负荷。这种普遍的模式可以被抽象出来,并且趋向于正常工作。注意:一个重要的部分是从加载回调调用doSomething()
,而不是actuallyDoIt()
,原因很明显,如果您不希望代码不同步。
你如何抽象上述模式取决于你的具体用例。您可以拥有一个管理所有资源加载和获取的类,并使用映射来管理加载和不加载的内容,并允许调用者在资源不可用时设置回调。例如
public class ResourceManager
{
private var isResourceLoaded:Object = {};
private var callbackOnLoad:Object = {};
private var resources:Object = {};
public function getResource(resourceId:String, callBack:Function):void
{
if(isResourceLoaded[resourceId])
{
callback(resources[resourceId]);
}
else
{
callbackOnLoad[resourceId] = callBack;
loadResource(resourceId);
}
}
// ... snip the rest since you can work it out ...
}
我可能会使用事件而不是回调,但这取决于你。有时,管理所有资源的中央类不可能,在这种情况下,您可能希望将加载代理传递给能够管理算法的对象。
public class NeedsToLoad
{
public var asyncLoader:AsyncLoaderClass;
public function doSomething():void
{
asyncLoader.execute(resourceId, actuallyDoIt);
}
public function actuallyDoIt():void { }
}
public class AsyncLoaderClass
{
/* vars like original algorithm */
public function execute(resourceId:String, callback:Function):void
{
if(isResourceLoaded)
{
callback();
}
else
{
loadResource(resourceId);
}
}
/* implements the rest of the original algorithm */
}
再次,这是不难上述从与回调事件工作改变(我宁愿在实践中,但它是很难写为例如短码)。
重要的是看看上面两种抽象方法如何封装原始算法。这样你可以量身定制满足你需求的方法。
在最终抽象的主要决定因素将取决于:
- 谁知道资源的状态...调用上下文或服务抽象?
- 你是否需要一个中心位置来获取...的资源以及使得这个中心位置在整个程序中都可用的麻烦(呃...单身人士)
- 你的程序的加载需求真的很复杂吗? (例如,可以以这样的方式编写该抽象,使得在资源列表可用之前不会执行该功能)。