2017-01-12 3 views
1

私は、サーバーの速度と負荷を最適化しようとするために、次の処理を行っています。しかし、物事は順不同で始まり、なぜ私は確信していません。それは私に、私が理解していない何かが起こっていると信じさせる。ここでは、コードは次のようになります。Angular2:コールバックとREST API呼び出しによる再帰

getInfo (startIndex, endIndex) { //starts with 0, 3 as the two params 
    var arr = globalArray.splice(startIndex, endIndex); 
    var tempThis = this; 
    this.function1(arr, function() { 
     this.function2(arr, function() { 
      if (end != tempThis.globalArray.length - 1) { 
       var newStart = endIndex; 
       var newEnd = endIndex + 3; 
       if (newEnd > tempThis.globalArray.length - 1) { 
        newEnd = tempThis.globalArray.length - 1; 
       } 
       console.log("about to recurse"); 
       tempThis.getInfo(newStart, newEnd); 
      } 
     }) 
    }) 

} 

function1 (list) { 
    list.forEach(function (thing) { 
     httpCall(params, function (data, error) { 
      //logic 
      if(list.indexOf(thing) == list.length - 1) { 
       callback(); 
      } 
     }) 
    }) 
} 

function2 (list) { 
    list.forEach(function (thing) { 
     httpCall(params, function (data, error) { 
      //logic 
      if(list.indexOf(thing) == list.length - 1) { 
       callback(); 
      } 
     }) 
    }) 
} 

このプロセスの意図はシーケンシャルすべてを取得することです。だから、私は大規模なglobalListを持っています。私はそれを一度に3つ分けて、私の論理を通して送る。私はコールバックを呼び出すミニリストの最後のインデックス上にあることを見つけるとfunction2のロジックに移動する必要があります。その後、インデックスをインクリメントして再帰する必要があります。

私がコールバックで理解したことは、基本的にプロセスを同期させるべきだということです。しかし、コールバックは予測不能な順序で呼び出されており、多くの場合、頻繁に呼び出されています。私はfunction1と2の論理が健全だと感じています。

質問:私の理解は間違っていますか?このプロセスは良いことではありませんか?

答えて

2

をfunction1/function2 forEachのコードは、HTTP呼び出しが非同期であるため、非同期で処理されます。これは、関数に渡される小さなリストに3つの項目がある場合、3つのHTTP呼び出しが別々の時点で処理され処理されることを意味します。あなたが要求をした順にコールが完了するという保証はないので、3つのコールのうち最後のコールが完了してから、もう一方のコールが完了し、コールバックが開始される前にコールバックが発生する状況があります。完了しました。インデックスを見るのではなく、これまでに処理された処理の数を把握することで、この問題を解決することができます。

function processPart1(list, callback) { 
    let numProcessed = 0; 

    list.forEach(function (item) { 
     httpCall(params, function (data, error) { 
      //logic 

      numProcessed++; 

      if (numProcessed === list.length) { 
       callback(); 
      } 
     }); 
    }); 
} 

あなたの周りのコールバックを渡すと非同期プロセスは同期的に動作するように管理しようとするこのアプローチを見つける問題は、それが読みにくい得ることができるということであり、このようなバグはに切り替える。でクリープすることができます約束ベースの技術は、これらの両方を手助けすることができます。 Qのような約束のライブラリには、これらの両方を手助けする機能があります。たとえば、Qには非同期アクションのリストを処理し、すべてが完了した後に作業するメソッド(Q:Qall)があります。

さらに、呼び出されるコードは、コードの終了時に必要なコードについて知る必要はありません。プロミスは、非同期プログラミングの性質から生じる問題を解決するベストプラクティスの1つと考えられます。現在、多くのライブラリには、HTTP呼び出し(すなわちjQuery)に対する約束に基づくアプローチが含まれています。

Qのようなライブラリを使用すると、次のようなことができます。これは、すべてを編成する約束を使って物事を潜在的に行う方法を示す例です。

function getInfo(startIndex, endIndex) { //starts with 0, 3 as the two params 
    var arr = globalArray.splice(startIndex, endIndex); 
    var tempThis = this; 

    Q.all(arr.map(function (item) { 
     return processItemPart1(item)); 
    })) 
    .then(function() { // this is called when all part 1 promises resolve 
     return Q.all(arr.map(function (item) { 
      return processItemPart2(item); 
     })); 
    }) 
    .then(function() { // this is called when all part 2 promises resolve 
     if (end != tempThis.globalArray.length - 1) { 
      var newStart = endIndex; 
      var newEnd = endIndex + 3; 
      if (newEnd > tempThis.globalArray.length - 1) { 
       newEnd = tempThis.globalArray.length - 1; 
      } 
      console.log("about to recurse"); 
      tempThis.getInfo(newStart, newEnd); 
     } 
    }) 
    .fail(function() { // this is called when an error occurs 
     // do anything on error 
    }) 
    .done(); 
} 

function processItemPart1(item) { 
    // This is one way using the library to make the HTTP call 
    // promise-based. 
    return Q.Promise(function (resolve, reject) { 
     httpCall(params, function (data, error) { 
      if (error) { 
       // logic for error 
       reject(new Error(error)); 
       return; 
      } 

      // logic for success 
      resolve(); 
     }); 
    }); 
} 

function processItemPart2(item) { 
    // This is another way using the library to make the HTTP call 
    // promise-based. 
    let deferred = Q.defer(); 

    httpCall(params, function (data, error) { 
     if (error) { 
      // logic for error 
      deferred.reject(new Error(error)); 

      return; 
     } 

     // logic for success 
     deferred.resolve(); 
    }); 

    return deferred.promise; 
} 

function processItemPart3IfThereWasOne(item) { 
    // This is another way using the Q library with a library like jQuery 
    // whose ajax calls actually return a promise. 
    return Q($.ajax(params)) 
    .then(function() { 
     // logic 
    }); 
} 

資源:

Qライブラリのドキュメント:https://github.com/kriskowal/q

1

私は今同様の問題に直面しています。コールバックは定義上非同期であり、httpクライアントはデータを非同期に管理するために設計されたobservablesを返します。

私は今、アクションの「流れ」を管理することで、この問題を解決することができたngrxに探しています。 - よりシームレスにデータがにあるであろう状態間を遷移させる(別名時間にわたる一連のコマンドを)

関連する問題