Actionscript 3 as3加载架构
我有一个大型应用程序,在调用依赖于所述加载项的其他例程之前,需要确保加载各种项(在不同的时间,而不仅仅是在启动时)。我发现的问题是,我的体系结构最终是如何支持这一点的:它要么充斥着回调(和嵌套回调!),要么预先填充了几十个整洁的小回调Actionscript 3 as3加载架构,actionscript-3,architecture,Actionscript 3,Architecture,我有一个大型应用程序,在调用依赖于所述加载项的其他例程之前,需要确保加载各种项(在不同的时间,而不仅仅是在启动时)。我发现的问题是,我的体系结构最终是如何支持这一点的:它要么充斥着回调(和嵌套回调!),要么预先填充了几十个整洁的小回调 private function SaveUser_complete(params:ReturnType):void { continueOnWithTheRoutineIWasIn(); } 等等。目前,代码库大概只有2500行,但它将增长到大约
private function SaveUser_complete(params:ReturnType):void
{
continueOnWithTheRoutineIWasIn();
}
等等。目前,代码库大概只有2500行,但它将增长到大约10k。我只是看不到任何其他的方法来解决这个问题,但它似乎是错误的(而且很费劲)。此外,我还研究了pureMVC、Cairngorm,这些方法似乎同样乏味,除了另一层抽象之外。有什么建议吗?异步操作在代码基础上总是有这样的影响,不幸的是,您可以做的事情并不多。如果您的加载操作形成某种“服务”,那么最好创建一个iSeries接口,以及适当的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(URL或其他)到消息名的映射,无论哪种方式,最好从模型(在同一个命令中)获取此信息:
希望这样您就可以调用命令“callService”,或者无论您如何触发它,您都可以在代码中或可能通过解析的XML配置callbackMap/switch。
希望这能让你开始,就像我刚刚意识到的,是相关的吗
编辑:
大家好,刚才又通读了一遍你们要解决的问题,我想你们描述的是一系列有限状态,即状态机。
似乎大致上您的序列是FunctionState->LoadingState->ResultState。这可能是一种更好的管理小异步“链”负载的通用方法。异步操作总是会对代码库产生这种影响,不幸的是,您可以做的并不多。如果您的加载操作形成某种“服务”,那么最好创建一个iSeries接口,以及适当的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(URL或其他)到消息名的映射,无论哪种方式,最好从模型(在同一个命令中)获取此信息:
希望这样您就可以调用命令“callService”,或者无论您如何触发它,您都可以在代码中或可能通过解析的XML配置callbackMap/switch。
希望这能让你开始,就像我刚刚意识到的,是相关的吗
编辑:
大家好,刚才又通读了一遍你们要解决的问题,我想你们描述的是一系列有限状态,即状态机。
似乎大致上您的序列是FunctionState->LoadingState->ResultState。这可能是管理小型异步“链”负载的更好的通用方法。同意enzuguri。不管怎样,您都需要大量回调,但是如果您可以为所有回调定义一个接口,并将代码放入控制器类或服务管理器中,并将所有回调都放在一个地方,那么回调就不会变得势不可挡 同意恩祖古里的观点。不管怎样,您都需要大量回调,但是如果您可以为所有回调定义一个接口,并将代码放入控制器类或服务管理器中,并将所有回调都放在一个地方,那么回调就不会变得势不可挡 我知道你在经历什么。不幸的是,我从未见过一个好的解决方案。基本上异步代码就是这样结束的 一种解决方案算法:
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()
,原因很明显,如果您不希望代码失去同步
如何抽象上述模式取决于您的特定用例。您可以有一个单独的类来管理所有资源的加载和获取,并使用映射来管理加载的和未加载的,并且允许调用方在资源不可用时设置回调。e、 g
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 */
}
同样,将上述内容从使用回调更改为事件并不困难(我更愿意在实践中使用回调,但要为此编写简短的示例代码则比较困难)
重要的是要了解上述两种抽象方法仅仅是如何封装原始算法的。这样,您就可以定制一种适合您需要的方法
最终抽象的主要决定因素取决于:
- 谁知道资源的状况。。。调用上下文还是服务抽象
- 您是否需要一个中心位置从…获取资源。。。在你的整个计划中,让这个中心位置都可用的麻烦(啊…单身人士)
- 程序的加载需求到底有多复杂?(例如,编写此抽象的方式可以使函数在资源列表可用之前不会执行)
- 我知道你在经历什么。不幸的是,我从未见过一个好的解决方案。基本上异步代码就是这样结束的
一种解决方案算法:
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();
}
}
这种模式允许您进行延迟加载,但也可以在必要时强制加载。这个通用模式可以抽象出来,并且可以