2009-08-10 141 views
1

我有一个大型应用程序需要确保在调用其他依赖于所述加载项目的例程之前加载各种项目(在不同的时间,而不仅仅是在启动时)。我觉得有问题是我的架构是如何结束了寻找支持这一点:它要么回调遍野,或预先与数十家整洁的小as3加载体系结构

private function SaveUser_complete(params:ReturnType):void 
{ 
     continueOnWithTheRoutineIWasIn(); 
} 

等人口密集(和嵌套回调!)。目前代码库只有2500行,但它将增长到大概10k左右。我只是看不到任何其他方式,但它似乎是错误的(和辛苦)。另外,我研究过pureMVC和Cairngorm,除了另一层抽象外,这些方法看起来同样乏味。有什么建议么?

回答

1

好吧,异步操作总是会对代码库产生这种影响,不幸的是,你并不能做很多事情。如果您的加载操作形成某种“服务”,那么最好制作一个IService接口,以及适当的MVC Style架构并使用数据令牌。简述:

//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(网址或其他)的到消息名称,无论哪种方式最好得到一个模型此信息(在相同的命令):

private function workOutMessageNameHere(commandParams):String 
{ 
    var model:CallbackModel = frameworkMethodOfRetrivingModels(); 
    return model.getMessageNameForAsyncCommand(commandParams); 
} 

这样应该可以只留给你调用命令“callService”或不过你触发它,你可以配置代码中的回调映射/切换或可能通过解析的XML。 希望这能让你开始,正如我刚刚意识到的,是相关的?你好,只是又一次通读了你正在试图解决的问题,我想你正在描述一系列有限状态,即一个状态机。 似乎你的序列大致是FunctionState - > LoadingState - > ResultState。这可能是更好的一般方法来管理小异步'链'的负载。

0

同意enzuguri。不管怎样,你都需要大量的回调函数,但是如果你可以为它们定义一个单一的接口,并将代码推送到控制器类或服务管理器中,并将它们集中到一个地方,那么它就不会变得不堪重负。

0

我知道你正在经历什么。不幸的是,我从未见过一个好的解决方案基本上,异步代码只是以这种方式结束。

一个解决方案算法:

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 */ 
} 

再次,这是不难上述从与回调事件工作改变(我宁愿在实践中,但它是很难写为例如短码)。

重要的是看看上面两种抽象方法如何封装原始算法。这样你可以量身定制满足你需求的方法。

在最终抽象的主要决定因素将取决于:

  • 谁知道资源的状态...调用上下文或服务抽象?
  • 你是否需要一个中心位置来获取...的资源以及使得这个中心位置在整个程序中都可用的麻烦(呃...单身人士)
  • 你的程序的加载需求真的很复杂吗? (例如,可以以这样的方式编写该抽象,使得在资源列表可用之前不会执行该功能)。
0

在我的一个项目中,我构建了基本上是包装类的自定义加载器。我正在发送它的元素数组加载和等待完成或失败的事件(我进一步修改它,并增加了优先级)。所以我不必为所有资源添加如此多的处理程序。

您只需要监视哪些资源已被下载,以及何时完成所有资源,调度自定义event-resourceDownloaded或其他resourcesFailed。

你也可以在每个资源上加上一个标志,说明它是必要的还是强制的,如果不是强制的,不要在失败的资源上抛出失败的事件并继续监视其他资源!

现在优先考虑,你可以有一堆你想先显示的文件,显示并继续在后台加载其他资源。

你可以这样做,相信我你会喜欢它!

0

您可以检查Masapi框架,看它是否满足您的需求。

您还可以调查源代码以了解他们如何解决问题。

http://code.google.com/p/masapi/

这是很编写和维护。我在使用Air开发的桌面RSS客户端中成功使用了它。

它的工作非常好,假设您在并行加载太多资源时注意开销。