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();
          }
      }
      
      这种模式允许您进行延迟加载,但也可以在必要时强制加载。这个通用模式可以抽象出来,并且可以