2009-08-10 9 views
1

私は、ロードされたアイテムに依存する他のルーチンを呼び出す前に、さまざまなアイテムがロードされることを確実にする必要がある大きなアプリケーションを持っています。それはコールバックが散らばっているか、小ぎれいなas3ローディングアーキテクチャ

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

などによる前人口(およびネストされたコールバック!):私は、問題を見つけることは、私のアーキテクチャがこれをサポートするために探して終了方法です。現在のコードベースはおそらく2500行に過ぎませんが、おそらく10k程度にまで成長するでしょう。私はちょうどこれの周りの他の方法を見ることはできませんが、それはとても間違って(と面倒なようです)。また、私はpureMVC、Cairngormを見てきました。これらのメソッドは、別の抽象レイヤーを除いて、同じように退屈なようです。助言がありますか?

答えて

1

よく非同期操作は、コードベースにこの影響を与えます。残念ながら、実際には多くのことができません。ロード操作が何らかの「サービス」を形成する場合は、適切なMVCスタイル・アーキテクチャーと一緒にIServiceインターフェースを作成し、データ・トークンを使用することが最善です。簡単に言えば:

私は言葉書かれている
//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や何でも)のマップを持っている可能性のいずれかメッセージ名に、いずれかの方法は、最高の(同じコマンドで)モデルからこの情報を取得:

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

これがうまくいけば、単に「callService」コマンドを呼び出すことであなたを残す必要があるか、あなたはそれをトリガーされますが、設定することができますcallbackMap/switch(コード内)、またはおそらく解析されたXML経由。 これはあなたが始めたことを願っています。私が今気づいたように、関連性がありますか?

編集: こんにちは、あなたは解決しようとしている問題をもう一度読んでいます。私はあなたが一連の有限状態、つまり状態マシンを記述していると思います。 あなたのシーケンスは、FunctionState - > LoadingState - > ResultStateのようです。これは、ほとんどの非同期チェーンの負荷を管理するためのより良い一般的なアプローチかもしれません。

0

エンズグリと同意する。何があってもたくさんのコールバックが必要ですが、それらのすべてのために単一のインターフェースを定義し、コードをコントローラークラスまたはサービスマネージャーに押し込んで、すべてを1か所にまとめることができれば、それは圧倒的にはなりません。

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

ここでも、イベントへのコールバックでの作業から上記を変更することは難しいことではありません(私は実際に好むだろうが、そのための短いサンプルコードを書くことが困難です)。

上記の2つの抽象のアプローチは、単にオリジナルのアルゴリズムをカプセル化する方法を確認することが重要です。そうすれば、ニーズに合ったアプローチを調整できます。リソースの状態を知っている

  • ...呼び出し側のコンテキストまたはサービスの抽象化:最終的な抽象化で

    主な決定要因はに依存しますか?

  • あなたはリソースを獲得するために中心的な場所を必要とします...そして、この中心的な場所をあなたのプログラム全体で利用できるようにするのは面倒です(シングルトン)
  • プログラムの読み込みの必要性は本当に複雑ですか? (例えば、リソースのリストが利用可能になるまで機能が実行されないように、この抽象化を書くことが可能である)。私のプロジェクトの一つで
0

、私は基本的にラッパークラスだったカスタムローダーを構築します。私はそれをロードし、完全または失敗したイベントをロードするための要素の配列を送信していました(さらに、私はそれを修正し、優先順位も追加しました)。だから私はすべてのリソースのために非常に多くのハンドラを追加する必要はありませんでした。

あなただけのカスタムイベント-resourceDownloadedまたは他のresourcesFailedを派遣、すべてのリソースをダウンロードしたときにすべてのリソースが完了された監視する必要があります。

はまた、強制されていない場合、そのリソースの失敗に失敗したイベントを投げると、他のリソースの監視を継続していないことが、必要または強制的かそうでないと言って、すべてのリソースにフラグを置くことができます!

は今の優先度で、あなたが最初に表示したいファイルの束、ディスプレイを持っているし、バックグラウンドで他のリソースをロードし続けることができます。

これと同じことができますし、私があなたがそれを楽しむことができると信じて!

0

Masapiフレームワークがあなたのニーズを満たすかどうか確認することができます。

ソースコードを調査して、どのように問題に近づいたかを知ることもできます。

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

これはよく書かれており、維持しています。私はAirで開発したデスクトップRSSクライアントでうまく使用しました。

これは、並行して、あまりにも多くのリソースをロードしている間、あなたが頭上に注意を払うと仮定すると非常によく働きました。