11

次のような関数でいっぱいのオブジェクトがあります。

var functions = {
    fun1 : function(){ ... }
    fun2 : function(){ ... }
    fun3 : function(){ ... }
};

オブジェクト キーはすべて、次のように配列内で参照されます。

var funList = ['fun1','fun2','fun3'];

私は配列を使用してすべての関数を実行しています。

$.each(funList, function(i,v){
    functions[v].call(this, args);
});

私の問題はこれです。次のように、すべての関数の実行を延期する方法が必要です。

  1. $.each ループでは、関数はシリアルに実行されます
  2. 配列/オブジェクト内のすべての関数が完了するまで、後続のコードの実行を延期するメソッド。

これには $.map メソッドを使用する必要があると読んだことがありますが、それを理解するのに苦労しています。

4

2 に答える 2

8

うわー... これは演習でした。$.Deferred() を理解するのは少し難しかったですが、思い通りに動作するようになりました! これがどれほど合理化されているかはわかりませんが、おそらく他の人がより効率的にすることができます.

その要点は、.pipe() を使用して deferred のチェーンを作成することです。

編集:私のコード(以下)は、参照キーリストに2つ未満のオブジェクトを収容しません。任意のサイズのキー リストで動作するように jsfiddle を更新しました。


以下のすべてが JSFiddle で動作していることを確認できます: http://jsfiddle.net/hBAsp/3/


これが私がそれをどのように解決したかのステップバイステップです:

  1. 関数でいっぱいのオブジェクトと参照キーの配列から始めます (処理したい順序で)。関数は、完了時に解決する遅延オブジェクトを受け取ることを期待する必要があります。

    var obj = {
        one: function(dfd){
            /* do stuff */
            dfd.resolve();
        },
        two: function(dfd){...},
        three: function(dfd){...},
        etc...
    };
    var keys=['one','two','three', etc...];`
    
  2. プロミスを初期化関数に渡すメインの遅延ラッパーを作成します。関数にコードを追加していきます。

    var mainDeferred = $.Deferred(function(mainDFD){
    
  3. その初期化関数内で、遅延オブジェクトの配列を作成し、最初の遅延オブジェクトを手動で作成します。

    var dfds = [$.Deferred()];
    
  4. 次に、for ループを使用して、2 番目のキー リストの最後から 2 番目の項目を調べます。我々は次のようになります:

    1. ステップスルーする各アイテムの遅延オブジェクトを作成する
    2. obj からキー関連関数を実行する無名関数を設定し、新しく作成した Deferred オブジェクトを解決するために obj に渡します
    3. その新しく作成された関数を以前に作成された Deferred オブジェクトにパイプします (そのため、最初のオブジェクトを手動で作成する必要がありました)。
    4. JavaScript スコープの問題を回避するには、for リストで囲まれたループを使用する必要があります。

      for (i=1; i<keys.length-1; i++){
          (function(n){
              dfds.push($.Deferred());
              dfds[i-1].pipe(function(){
                  obj[keys[n]].call(this,dfds[n]);
              });
          })(n);
      };
      
  5. 最後の無名関数を手動で作成し、それをリスト内の最後から 2 番目の遅延オブジェクトにパイプします。最後のプロセスが実行されるとすぐにシバン全体が完全に起動するように、解決のためにメインの遅延オブジェクトを渡す必要があるため、これを手動で行います。

    dfds[keys.length-2].pipe(function(){
        obj[keys[keys.length-1]].call(this,mainDFD);
    });
    
  6. パイプライン全体が構築されたので、あとは最初のオブジェクトを起動し、解決のために最初の deferred を割り当てるだけです。

    obj[keys[0]].call(this,dfds[0]);
    
  7. メインの遅延初期化関数を閉じる必要があります (これは、遅延が作成されるとすぐにすべて起動します。

    });
    
  8. これで、関数をメイン オブジェクトにパイプして、前の要素がすべて実行された後に実行することもできます。

    mainDeferred.pipe(function(){
        /* do other stuff */    
    });
    
于 2012-08-09T18:01:59.003 に答える
1

パイプを使用して、コールバック関数を配列としてパイプできると思います。ここにがあります。

var a = $.Deferred();

var b = $.Deferred();

var c = $.Deferred();

var checkA = function() {
  console.log('checkA');
  return a.resolve();
};


var checkB = function() {
  console.log('checkB');
  return b.resolve();
};

var checkC = function() {
  console.log('checkC');
  return c.reject();
};

checkAll = $.Deferred().resolve().promise();
checkAll = checkAll.pipe(checkA);
checkAll = checkAll.pipe(checkB);
checkAll = checkAll.pipe(checkC);

checkAll.done(function() {
  return console.log('checkAll done');
}).fail(function() {
  return console.log('checkAll fail');
});

出力は次のようになります

"checkA"
"checkB"
"checkC"
"checkAll fail"

別の結果を見たい場合は、チェック機能で結果の「解決」を「拒否」に変更できます。例: checkA を reject に変更した場合。

var checkA = function() {
  console.log('checkA');
  return a.reject();
};

出力は次のようになります。

"checkA"
"checkAll fail"

checkA が拒否されるため、checkB と checkC には進みません。配列で関数を呼び出すことができるように

funList = [checkA, checkB, checkC];
for(var i=0; i<funList.length; i++){
  checkAll = checkAll.pipe(funList[i]);
}

ノート。コールバックが常に Deferred オブジェクトを返すようにする必要があります。

于 2015-07-06T09:07:18.807 に答える