1

Qやのようなライブラリのかなり典型的な使用例のようasyncに思えますが、それを行うための最良の方法が何であるかを実際に理解することはできませんでした.

node-csv(を使用して) 150 行の CSV ファイルをインポートし、行ごとに mongo ドキュメントを作成したいと考えています。ただし、ストリームの解析は「db inserts」よりも速く終了するように見えるため、コールバックの呼び出しが早すぎるという問題に遭遇します。

// importtest.mocha.js
[...]
importer.loadFromCsv (url, function(result) {
 result.length.should.be.equal (150); // nope, it's always around 41
}


// importer.js 
function loadFromCsv (url, callback){
  csv().from.stream(url)
    .on ('record', function(record, index){ 
       new Row({data: record}).save(function() {
         console.log ('saved a row to db');
       }); 
    })
    .on ('end', function() {
      callback (Row.find({})); // E parser finished, but probably not all Row.save()
    });
}

それで、ストリームの解析/データベースの挿入が非同期である間、最後のコールバックがすべての挿入が終了した後にのみ行われるように、async/promisesでそれを修正する方法を教えてください。

4

1 に答える 1

1

多くのレコードを挿入するため、それぞれのレコードを個別に処理する必要があります。これは、試して適応できる、テストされていないコード スニペットです。実際には、promise のリストを作成します。すべてが解決されると、 then(fn) に渡された関数が起動されます。コードで述べたように、エラーのあるレコードには注意する必要があります。then(fn) に渡された関数は、すべての promise が解決された (成功した) 場合にのみ実行されることに注意してください。promise がレコードのエラーであることを示すには、def.resolve() の代わりに defer.reject() を使用する必要があります。onErrorFn プレースホルダーの関数も渡します。そのようなSQLトランザクションのようなものです。

コメントを含むコードは次のとおりです。

var q = require('q');

function loadFromCsv (url, callback){
  // create an array holding all promises
  var csv_promises = [];

  csv().from.stream(url)
    .on ('record', function(record, index){ 
      // create new defer object, per row
      var row_defer = q.defer();

      // make sure, this function gets called, only after the row got saved
      new Row({data: record}).save(function() {
        console.log ('saved a row to db');

        // resolves the promise, per row
        row_defer.resolve(record);

        // todo: take care for an error, per row
      });

      csv_promises.push(row_defer.promise);     // add promise to promise list, per row
    })
    .on ('end', function() {
      // callback (Row.find({})); // E parser finished, but probably not all Row.save()

      // q.all gets resolved and fires passed function as soon as ALL promises in csv_promises array are resolved
      // todo: take care for errors
      q.all(csv_promises).then(function() {
        callback( csv_promises );
      } /*, onErrorFn */ );
}

loadFromCsv( "URL", function(rows) {
    console.log("Treated rows: ", rows.length);
});
于 2013-12-14T11:55:31.560 に答える