我知道你正在經歷什麼。不幸的是,我從未見過一個好的解決方案基本上,異步代碼只是以這種方式結束。
一個解決方案算法:
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 */
}
再次,這是不難上述從與回調事件工作改變(我寧願在實踐中,但它是很難寫爲例如短碼)。
重要的是看看上面兩種抽象方法如何封裝原始算法。這樣你可以量身定製滿足你需求的方法。
在最終抽象的主要決定因素將取決於:
- 誰知道資源的狀態...調用上下文或服務抽象?
- 你是否需要一箇中心位置來獲取...的資源以及使得這個中心位置在整個程序中都可用的麻煩(呃...單身人士)
- 你的程序的加載需求真的很複雜嗎? (例如,可以以這樣的方式編寫該抽象,使得在資源列表可用之前不會執行該功能)。