1. ホーム
  2. javascript

[解決済み] Node JSのPromise.allとforEach

2022-04-29 09:19:34

質問

私は、非同期メソッドを公開する配列のような構造体を持っています。非同期メソッド呼び出しは、順番に、より多くの非同期メソッドを公開する配列構造を返します。私はこの構造から得られた値を格納するために別のJSONオブジェクトを作成しているので、私はコールバックで参照を追跡することに注意する必要があります。

私はブルートフォースソリューションをコーディングしましたが、よりイディオムまたはクリーンなソリューションを学びたいと思います。

  1. パターンは、nレベルの入れ子に対して反復可能であるべきである。
  2. promise.allかそれに類するテクニックを使って、いつ囲むルーチンを解決するかを決める必要があります。
  3. すべての要素が必ずしも非同期呼び出しに関係するとは限りません。そのため、ネストされたpromise.allでは、インデックスに基づいてJSON配列の要素に単純に代入することはできないのです。それでも、ネストされたforEachでpromise.allのようなものを使って、内包するルーチンを解決する前に、すべてのプロパティの割り当てが行われたことを確認する必要があるのです。
  4. 私はbluebird promise libを使用していますが、これは必須条件ではありません。

以下はコードの一部です。

var jsonItems = [];

items.forEach(function(item){

  var jsonItem = {};
  jsonItem.name = item.name;
  item.getThings().then(function(things){
  // or Promise.all(allItemGetThingCalls, function(things){

    things.forEach(function(thing, index){

      jsonItems[index].thingName = thing.name;
      if(thing.type === 'file'){

        thing.getFile().then(function(file){ //or promise.all?

          jsonItems[index].filesize = file.getSize();

解決方法は?

簡単なルールがあるので、とてもわかりやすいですね。

  • でプロミスを作成すると、必ず then を返します。 - を返さないプロミスは、外で待たされることはないでしょう。
  • 複数のプロミスを作成した場合 .all それら - そうすれば、すべてのプロミスを待ち、どれからのエラーも黙殺されることはありません。
  • ネストするたびに then の場合、通常、途中で戻ることができます。 - then チェーンは通常、せいぜい1レベルまでの深さしかありません。
  • IOを実行するときは、必ずプロミスで行うこと - プロミスの中に入れるか、プロミスを使用して完了を知らせるか、どちらかでなければなりません。

そして、いくつかのヒント。

  • マッピングは .map よりも for/push - 関数で値をマッピングしている場合。 map を使うと、アクションをひとつずつ適用して結果を集約するという概念を簡潔に表現することができます。
  • 同時実行は自由であれば、順次実行よりも優れている - 同時並行で実行し、待つ方が良いのです Promise.all 次から次へと実行し、それぞれが次の実行の前に待機するよりも。

OK、では早速始めましょう。

var items = [1, 2, 3, 4, 5];
var fn = function asyncMultiplyBy2(v){ // sample async action
    return new Promise(resolve => setTimeout(() => resolve(v * 2), 100));
};
// map over forEach since it returns

var actions = items.map(fn); // run the function over all items

// we now have a promises array and we want to wait for it

var results = Promise.all(actions); // pass array of promises

results.then(data => // or just .then(console.log)
    console.log(data) // [2, 4, 6, 8, 10]
);

// we can nest this of course, as I said, `then` chains:

var res2 = Promise.all([1, 2, 3, 4, 5].map(fn)).then(
    data => Promise.all(data.map(fn))
).then(function(data){
    // the next `then` is executed after the promise has returned from the previous
    // `then` fulfilled, in this case it's an aggregate promise because of 
    // the `.all` 
    return Promise.all(data.map(fn));
}).then(function(data){
    // just for good measure
    return Promise.all(data.map(fn));
});

// now to get the results:

res2.then(function(data){
    console.log(data); // [16, 32, 48, 64, 80]
});