我有一个大型应用程序,它需要确保在调用依赖于所述加载项的其他例程之前加载了各种项(在不同的时间,而不仅仅是在启动时)。我发现的问题是我的体系结构最终是如何支持这一点的:它要么到处都是回调(和嵌套的回调!),要么预先填充了几十个整齐的小回调
private function SaveUser_complete(params:ReturnType):void
{
continueOnWithTheRoutineIWasIn();
}以此类推。目前代码库可能只有2500行,但它可能会增长到10k左右。我就是看不到其他的办法,但这似乎是错误的(和费力的)。此外,我还研究了pureMVC和凯恩,这些方法看起来同样单调乏味,只是有了另一个抽象层。有什么建议吗?
发布于 2009-08-10 10:33:13
异步操作总是会对代码库产生这种影响,不幸的是,您可以做的并不多。如果您的加载操作形成了某种“服务”,那么最好是创建一个IService接口,以及适当的MVC样式架构,并使用数据令牌。简要地说:
//In your command or whatever
var service:IService = model.getService();
var asyncToken:Token = service.someAsyncOperation(commandParams);
//some messaging is used here, 'sendMessage' would be 'sendNotification' in PureMVC
var autoCallBack:Function = function(event:TokenEvent):void
{
sendMessage(workOutMessageNameHere(commandParams), event.token.getResult());
//tidy up listeners and dispose token here
}
asyncToken.addEventListener(TokenEvent.RESULT, autoCallBack, false, 0, true);在我写“workOutMessageNameHere()”的地方,我假设你想要自动化的部分,你可以有某种巨大的开关,或者commandParams (urls或任何东西)到消息名称的映射,无论哪种方式,最好从模型(在相同的命令中)获取此信息:
private function workOutMessageNameHere(commandParams):String
{
var model:CallbackModel = frameworkMethodOfRetrivingModels();
return model.getMessageNameForAsyncCommand(commandParams);
}这应该只是让你调用命令'callService‘,或者无论你触发它的方式是什么,你可以在代码中配置callbackMap /开关,也可以通过解析的XML来配置。希望这能让你入门,而且我刚刚意识到,这是相关的吗?
编辑:嗨,我刚刚又读了一遍你试图解决的问题,我认为你描述的是一系列有限状态,即状态机。看起来你的序列大概是FunctionState -> LoadingState -> ResultState。这可能是管理小异步“链”负载的一种更好的通用方法。
发布于 2009-08-10 12:20:16
同意佐古里的观点。无论如何,您都需要大量的回调函数,但是如果您可以为所有这些回调函数定义一个接口,并将代码放到控制器类或服务管理器中,并将所有这些都放在一个地方,那么就不会变得不堪重负。
发布于 2009-08-10 17:09:33
我知道你在经历什么。不幸的是,我从来没有看到过一个好的解决方案。基本上,异步代码就是这样结束的。
一种解决算法:
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 */
}同样,从使用回调到事件(在实践中我更喜欢这样做,但为此编写简短的示例代码)来更改上面的内容并不难。
重要的是要了解上面两种抽象方法是如何封装原始算法的。这样,您就可以定制一种适合您需求的方法。
最终抽象中的主要决定因素将取决于:
了解资源状态的
https://stackoverflow.com/questions/1252659
复制相似问题