2017-05-06 20 views
0

一般的にノードの非同期性に問題があります。誰かがこのコードブロックで私を助けることができますか?いろいろな理由で、私は作業しているデータベースに一度に1行しか挿入できません。そして、実際には、短い遅延を追加して1秒間に1行だけをデータベースに挿入することができればさらに良いでしょう。Javascript/Node.js非同期ループ

ここに私のjsコードの短いセクションです。

console.log('*** Inserting Records ***') 
insertPromises = [] 
_.each(dbRecords, function (item) { 
    var insertItem = buildRecord(item) 
    insertPromises.push(conn.create(insertItem)) 
}) 
Promise.all(insertPromises).then(function (res) { 
    _.each(res, function (item) { 
     if (!item.success) { 
      console.log("### Error ### " + JSON.stringify(res[i].errors)) 
     } 
    }) 
    console.log('*** Inserted ' + res.length + ' Contacts') 
}) 

私の主な質問は、ループを続行する前にconn.createの約束を待つように強制する方法です。そして、1秒間に1回の繰り返しにループを遅らせる方法はありますか?

+0

その回答は役に立ちましたか? – Jbird

答えて

1

上記の再帰コードを使用する代わりに、async/awaitモデルを確認することができます。

これを使用する例は次のようになります。

async function processRecords(dbRecords) { 

    for (let item of dbRecords) { 
     try { 
      let insertItem = buildRecord(item) 
      await conn.create(insertItem) 
      await delay(1000) 
     } catch (e) { 
      //handle error... 
     } 
    } 

} 

function delay(ms) { 
    return new Promise((resolve) => setTimeout(resolve, ms)) 
} 

processRecords(dbRecords) 

これはES7コードであり、あなたはそれを変換するためにbabelコンパイラが必要です。

約束に追いついておらず、同期のようなコードに固執したい場合は、このようなものを使用する方が良いでしょう。

+0

あなたはそれを変換するためにバベルを必要としません。その構文はノード7.6以上で完全にサポートされています。 :) –

+0

いいね、言及してくれてありがとう!しかし、問題は彼が使用しているノードのバージョンは言及していないので、おそらくバベルが必要です! –

+0

nice ...私はこのアプローチが好きですが、UnhandledPromiseRejectionWarningを取得しています。私のコードはあなたの答えにあるものとほぼ正確です。 fyi - 完全に動作しています...ループを終了するときにエラーをスローします。 – Todd

1

簡単な解決策は、「挿入カウント」、つまり正常に挿入されたレコードの数を記録することです。これはあなたの配列ポインタになります。メソッドを使用して個々の約束を作成し、成功した応答ごとに「挿入カウント」を1ずつ増やします。

let insertCount = 0; 

function insertNextRecord() { 
    conn.create(buildRecord(dbRecords[insertCount]).then(function(res){ 
     insertCount += 1; 
     insertNextRecord(); 
    }).catch(function() { 
     console.log('Error while inserting record ' + insertCount); 
    }); 
} 

insertNextRecord(); 

これはテストされていないと私はあなたが表示されていないしているコードに関するいくつかの仮定を作ってるんです。

この例では想定しています

  • dbRecordsは、アレイ
  • conn.createが明示的に遅延を追加することを約束オブジェクト

を返し、あなたはそのようthenメソッド内でタイムアウトを使用することができています:

let insertCount = 0; 

function insertNextRecord() { 
    conn.create(buildRecord(dbRecords[insertCount]).then(function(res){ 
     insertCount += 1; 
     setTimeout(function() { 
      insertNextRecord(); 
     }, 500); 
    }).catch(function() { 
     console.log('Error while inserting record ' + insertCount); 
    }); 
} 

insertNextRecord(); 

このようにしなければならないのは残念です。多くのインサートを扱う場合、これは非常に遅くなります。

+1

これは現在のコードのように機能せず、再帰を持っています。このブロックは各dbクエリを順番に実行します。遅延を追加するには、単純に内側のinsertNextRecord()内にsetTimeoutを追加することができます。 –

+0

いいえ、あなたは現在のコードで、Promise.allを使用して、 'insertPromises'のすべての約束を解決してから解決します。言い換えれば、その約束は、すべての挿入リクエストが完了するまで解決されません。私が提供した例は、現在の要求が次の要求に移動する前に解決するのを待ちます。競合状態として知られている「遅延」を明示的に考慮する必要はありません。リクエスト '1'が完了した時点を知りたいのであれば、リクエスト '2'を行い、リクエスト 'B'が完了したらリクエスト '3'を...します。 – Jbird