0

ヘルパー クラスのインスタンスを作成したかったのですが、そのヘルパー クラスは外部スクリプトによる初期化が必要だったため、本質的に非同期でした。と

var obj = new myObj();

明らかに呼び出し

obj.myMethod();

obj は、そのメソッドとパラメーターが外部スクリプトによってロードされるまで空または未定義になるため、未定義になります。

はい、コールバック パターンを持ち、その中で新しいオブジェクトを操作するように物事を再構築することはできますが、私が取り組んできたように、多くの動的オブジェクトを含む大規模で多様な API を操作すると、面倒で扱いにくくなります。

私の質問は、これを巧みに回避する方法はありますか?

4

1 に答える 1

1

学術的に訓練されたプログラマーには、この種のアプローチの名前があると思いますが、どこかに書かれていない場合に備えて、ここに記載します。

私が行ったことは、プレースホルダー + キュー システムを使用して実行可能なオブジェクトを即座に返すようにローダー クラスを変更することです。

コンポーネントは次のとおりです。申し訳ありませんが、jQuery のビットが混在しています。これを純粋な JS スクリプトにすることは簡単にできますが、とにかくロードしたので怠け者です。

「クライアント」はこのリクエストを作成します。ここで、「呼び出し元」は私のハンドラー クラスです。

var obj = caller.use('myObj',args);

コーラーでは、

Caller.prototype.use = function(objname,args) {
    var _this = this;
    var methods = ['method1','method2'];
    var id = someRandomString();
    this.myASyncLoader(objname,function(){
        var q = [];
        if (_this.objs[id].loadqueue) {
            q = _this.objs[id].loadqueue;
        }
        _this.objs[id] = new myRemotelyLoadedClass(args);
        //realise all our placeholder stuff is now gone, we kept the queue in 'q'
        _this.objs[id].isloaded = true;
        //once again, the jquery is unnecessary, sorry
        $.each(q,function(a,b){
            _this.objs[id][b['f']](b['a']);
        });       
    });
    _this.objs[id] = _this.createPlaceholderObj(methods,id);
    return _this.objs[id];
}

この関数は基本的にローダー関数を開始し、それが完了すると、目的のクラスの新しいインスタンスをロードします。しかし、その間、すぐに何かを返します。これは、リモートでロードされたオブジェクトのすべてのメソッドとともにロードするプレースホルダー オブジェクトです。この例では、それらを配列で明示的に宣言する必要がありますが、これは少し面倒ですが、実行可能ですが、独自の目的のためにそれを行うより良い方法を考えることができると確信しています.

一時オブジェクトと未来オブジェクトの両方を、ランダム キーに関連付けられたクラス グローバル配列 'objs' に保持していることがわかります。

createPlaceholderObj メソッドは次のとおりです。

Caller.prototype.createPlaceholderObj = function(methods,id) {
var _this = this;
var n = {};
n.tempid = id;
n.isloaded = false;
$.each(methods,function(a,methodCalled){
        n[methodCalled] = function(){
        _this.queueCall(id,methodCalled,arguments);
    }
});
return n;
 }

ここでは、必要なメソッドを使用して新しい obj をロードしているだけであり、重要な ID も格納しています。新しいメソッドに 3 番目の関数 queueCall を割り当てます。この関数には、呼び出されたメソッドと、それが送信されたすべての引数が渡されます。その方法は次のとおりです。

Caller.prototype.queueCall = function(id,methodName,args) {
if (this.objs[id].isloaded == true) {
    this.objs[id][methodName](args);
} else {
    if (this.objs[id].loadqueue) {
        this.objs[id].loadqueue.push({'f':methodName,'a':args});    
    } else {
        var arr = [{'f':methodName,'a':args}];
        this.objs[id].loadqueue = arr;
    }
}
}

このメソッドは、ロジックが実際にロードされているかどうかに関係なく、クライアント スクリプトが新しいオブジェクト インスタンスのメソッドを呼び出すたびに呼び出されます。ここでの IF ステートメントは、どちらが該当するかをチェックします (非同期関数が完了するとすぐに、呼び出し元メソッドで isloaded が true に設定されます)。オブジェクトがロードされていない場合、methodName と引数がプレースホルダーのプロパティとしてキュー配列に追加されます。ロードされている場合は、メソッドを実行するだけです。

呼び出し元メソッドに戻ると、最後の説明のつかない部分で、キューがあるかどうかを確認し、キューがある場合はそれをループして、保存されているメソッド名と引数を実行します。

以上です!今私はできる:

var obj = caller.use('myObj',args);
obj.someMethod('cool');
obj.anotherMethod('beans');

これらのメソッドが実際に実行されるまでにわずかな遅延が発生する可能性がありますが、問題なく実行されます。

短すぎるソリューションではありませんが、大規模なプロジェクトに取り組んでいる場合は、これを 1 か所に配置するだけで、多くの見返りが得られます。

この質問に対するフォローアップを期待しています。たとえば、deferred-promise パターンを使用してこれをどのように行う人がいるのだろうか? または、他の方法がある場合は?または、このテクニックが何と呼ばれているか知っている人はいますか?JS whizzes からの入力は大歓迎です。

于 2012-07-29T16:09:46.283 に答える