Async: エラーが発生した後、async.map()から未処理のアイテムを判別する方法

作成日 2017年07月10日  ·  5コメント  ·  ソース: caolan/async

こんにちは、

map(...)を使用しているときに、iteratee関数から発行されたエラーを処理して、提供されたコレクションからまだ処理されていないアイテムの数を判別する方法はありますか?

mapを使用して、さまざまなurlsparamsなどの配列に対して複数の送信HTTPリクエストを実行しています(ノードrequestライブラリを使用)。これらのリクエストのいずれかを実行する途中で、特定のエラーが発生する場合があります。処理できるターゲット サーバーから取得できますが、作業中の現在のアイテムと、 mapがまだ取得していない残りのアイテムを再処理したいと思います。

コレクション内の正常に処理された(エラーなしの)各アイテムにフラグを設定し、関心のあるエラーが発生した場合は、それに応じて処理するのではないかと思いました。 次に、まだ処理されていないアイテムに対してフラグをfalseに設定してアイテムから新しい配列を作成し、これらに対してさらにmapを実行して、元のマップから元の最終コールバックを呼び出すようにします。

これが理にかなっているかどうかはわかりませんが、上記で説明したことを達成する方法はありますか?

question

最も参考になるコメント

こんにちは@ parky128 、質問ありがとう

iterateereflectラップしても機能しますか? reflect常に結果オブジェクトをcallbackに渡すため、 iteratee関数のエラーの1つが発生した場合でも、 mapは終了します。 次に、 mapからresultsオブジェクトを繰り返し処理し、 errorプロパティを持つオブジェクトを確認して、それに応じて処理することができます。 mapが取得していない可能性のあるアイテムを再処理する必要はありません。

async.map(coll, async.reflect(function(val, callback) {
  // your request code
}, function(err, results) {
  // err will always be null now
  results.forEach(function(result, i) {
    if (result.error) {
      // your code for handling errors
      // if `coll` is an array, you could access the value that caused 
      // this error through `coll[i]` as `map` preserves the order for arrays 
    } else {
      // otherwise `result.value` will contain the result of that `iteratee` call
    }
  });
});

それ以外の場合、質問に答えるために、 map常にarray返します。 その配列を反復処理して、どの値がundefinedかを確認できます。 これらは、エラーが発生したか、 undefinedcallbackに渡されたか、 errorが発生したときに進行中であったか、開始されなかったアイテムに対応します。 reflectアプローチはおそらくより安全なオプションですが、 undefinediteratee呼び出しからの有効な結果である可能性があるためです。

全てのコメント5件

こんにちは@ parky128 、質問ありがとう

iterateereflectラップしても機能しますか? reflect常に結果オブジェクトをcallbackに渡すため、 iteratee関数のエラーの1つが発生した場合でも、 mapは終了します。 次に、 mapからresultsオブジェクトを繰り返し処理し、 errorプロパティを持つオブジェクトを確認して、それに応じて処理することができます。 mapが取得していない可能性のあるアイテムを再処理する必要はありません。

async.map(coll, async.reflect(function(val, callback) {
  // your request code
}, function(err, results) {
  // err will always be null now
  results.forEach(function(result, i) {
    if (result.error) {
      // your code for handling errors
      // if `coll` is an array, you could access the value that caused 
      // this error through `coll[i]` as `map` preserves the order for arrays 
    } else {
      // otherwise `result.value` will contain the result of that `iteratee` call
    }
  });
});

それ以外の場合、質問に答えるために、 map常にarray返します。 その配列を反復処理して、どの値がundefinedかを確認できます。 これらは、エラーが発生したか、 undefinedcallbackに渡されたか、 errorが発生したときに進行中であったか、開始されなかったアイテムに対応します。 reflectアプローチはおそらくより安全なオプションですが、 undefinediteratee呼び出しからの有効な結果である可能性があるためです。

潜在的な解決策を提供するために時間を割いていただきありがとうございます。 実際には、 iteratee関数のいずれかが、キャッチしようとしている特定のエラーケースでエラーが発生するとすぐに、async.mapの最終コールバックが呼び出されるようにします。

ドキュメントを見ると、iterateeコールバック関数にエラーを渡すことでこれを達成できることがわかりますが、async.mapが呼び出す最後のコールバックで、その結果オブジェクトを使用して元のオブジェクトと比較できるかどうか疑問に思っていますコレクションを作成し、処理する必要があるものを確認します。

興味のあるエラーケースが返されるとすぐに、async.mapが他のリクエストの処理を試みたくありません。

興味のあるエラーケースが返されるとすぐに、async.mapが他のリクエストの処理を試みたくありません。

iterateeが非同期であるとすると、 async.mapは、最後のコールバックが呼び出されたときにすべてのアイテムの処理を開始します。 結果オブジェクトをコレクションと比較して、まだ処理が完了していないアイテムを確認できる可能性がありますが、それには落とし穴もあります。 たとえば、結果オブジェクトはiterateeの解決時に更新されるため、同期的に実行する必要があります。同じティックで、最後のコールバックが呼び出されます。

mapSeries試すことができます。 mapSeriesは、一度に1つのリクエストのみを実行します。 つまり、現在のアイテムが処理を終了したときにのみ次のアイテムを呼び出します(すべてを一度に開始するのではありません)。 これは、エラーが発生し、最後のコールバックが呼び出されると、 iterateeが実行されなくなることを意味します。 次に、結果をコレクションと比較して、まだ処理されていないアイテムを確認できます。 これはまだ少し回避策ですが、 async.mapを使用するよりも優れています。 ただし、このアプローチの主な欠点は、リクエストが並行して処理されなくなることです。

たとえば、コレクションが配列の場合

async.mapSeries(coll, function(val, callback) {
  // your iteratee function
}, function(err, results) {
  if (err) {
    // unprocessItems will include the item that errored.
    var unprocessItems = coll.slice(results.length - 1);
    // handle the unprocessedItems
  }
});

うーん、はい、私のiteratee関数は、リクエストライブラリを使用して発信httpリクエストを作成し、その結果をコールバックするため、非同期です。 したがって、反復するアイテムが10個あるとすると、4個が成功し、5個目が失敗し、エラーパラメータを指定してiteratee関数へのコールバックを呼び出します。つまり、async.mapへの最後のコールバックの結果オブジェクトには4つの成功した結果?

もしそうなら、今のところ私はそれがまだすべての発信呼び出しを行うという事実で生きます。 将来的には、配列を小さな配列に分割し、mapSeries内で小さなasync.mapsを実行して、リクエストがヒットしているターゲットサーバーへの最初のヒットを最小限に抑えることができます。

@hargasinski - async.reflectアプローチを使用することになりましたが、これはうまく機能しており、エラーが発生したすべてのアイテムを完全に表示できます:+1:

ありがとう!

このページは役に立ちましたか?
0 / 5 - 0 評価