2016-10-16 12 views
2

私は最近、javascriptの非同期動作のために約束とその目的を理解しようとしています。私は理解していると思うのですが、未来価値を返すものを約束する方法とまだ闘っておらず、何か他のことをするための新しいコードブロックを実行します。私が使用している二つの主要なノードモジュール:nodejs - ネストされた約束で読み取られたファイルを「約束する」のに役立ちます。

  • PG-約束
  • exceljs

私は何をしたいのですが、ファイルを読み込まれ、その後、一度完全に読み、実行する各ワークシートの反復DBコマンド。その後、すべてのワークシートが処理されたら、元のファイルを削除して削除します。ここに私のコードがあります。 私はそれが複数のワークシートがあるときでさえ、すべてがデータベースに書き込むポイントに作業しています。私は作業を持っていないことは、そのファイル

workbook.csv.readFile(fileName) 
      .then(function() { 
       // this array I was going to use to somehow populate a true/false array. 
       // Then when done with each sheet, push a true into the array. 
       // When all elements were true could signify all the processing is done... 
       // but have no idea how to utilize this! 
       // So left it in to take up space because wtf... 
       var arrWorksheetComplete = []; 

       workbook.eachSheet(function (worksheet) { 
        console.log(worksheet.name); 
        db.tx(function (t) { 
         var insertStatements = []; 
         for (var i = 2; i <= worksheet._rows.length; i++) { 
          // here we create a new array from the worksheet, as we need a 0 index based array. 
          // the worksheet values actually begins at element 1. We will splice to dump the undefined element at index 0. 
          // This will allow the batch promises to work correctly... otherwise everything will be offset by 1 
          var arrValues = Array.from(worksheet.getRow(i).values); 
          arrValues.splice(0, 1); 

          // these queries are upsert. Inserts will occur first, however if they error on the constraint, an update will occur instead. 
          insertStatements.push(t.one('insert into rq_data' + 
           '(col1, col2, col3) ' + 
           'values($1, $2, $3) ' + 
           'ON CONFLICT ON CONSTRAINT key_constraint DO UPDATE SET ' + 
           '(prodname) = ' + 
           '($3) RETURNING autokey', 
           arrValues)); 
         } 
         return t.batch(insertStatements); 
        }) 
        .then(function (data) { 
         console.log('Success:', 'Inserted/Updated ' + data.length + ' records'); 
        }) 
        .catch(function (error) { 
         console.log('ERROR:', error.message || error); 
        }); 
       }); 
      }); 
を取り除く行くために、すべてのワークシートが完全に処理されたときを識別するためにそれを設定している私は

.then(function(){ 
    // everything processed! 
    removeFile(fileName) 
    // this probably also wouldn't work as by now fileName is out of context? 
}); 

を言うことができるようにしたいと思い

しかし、私は約束の中で約束をしていると混乱しています。私は本質的に.eachSheet関数の中にネストされたdb.tx呼び出しを持っています。 ダムプログラマーが理解できるように助けてください!これを数時間壁に打ちつけている。 :)

+0

あなたは 'workbook.eachSheet'を約束し、それをチェーンする必要があります。また、 'eachSheet'呼び出しの外側で' db.tx'を移動する必要があります。これは、単一のデータベーストランザクションだけが必要なためです。 –

+0

あなたのすべての非同期オペレーションを宣言し、それらをネストしたら、それらを連鎖させる約束を返します。約束事と通常の非同期コールバックを混ぜてはいけません。 – jfriend00

+0

@ vitaly-t周りを見回していて、私はeachsheet関数を "約束する"方法を理解するのに苦労しています。あなたも私を指すことができる例はありますか? – dvsoukup

答えて

0

私が正しく理解すれば、あなたは約束を守ろうとしています。

私はあなたが直列に約束を実行する必要がある場合は、この記事はreduceを使用することを示唆しているあなたは、このgreat article on Promises anti-pattern(「コレクションKerfuffle」のセクションを参照してください)

を読むことをお勧めします。 promiseモジュールを含めることを忘れないでください

workbook.csv.readFile(fileName).then(function() { 

    processWorksheets().then(function() { 
    // all worksheets processed! 
    }); 

}); 

function processWorksheets() { 
    var worksheets = []; 

    // first, build an array of worksheet 
    workbook.eachSheet(function (worksheet) { 
     worksheets.push(worksheet); 
    }); 

    // then chain promises using Array.reduce 
    return worksheets.reduce(function(promise, item) { 
     // promise is the the value previously returned in the last invocation of the callback. 
     // item is a worksheet 

     // when the previous promise will be resolved, call saveWorksheet on the next worksheet 
     return promise.then(function(result) { 
      return saveWorksheet(item, result); 
     });   

    }, Promise.resolve()); // start chain with a 'fake' promise 
} 

// this method returns a promise 
function saveWorksheet(worksheet, result) { 

    return db.tx(function (t) { 

     var insertStatements = []; 
     for (var i = 2; i <= worksheet._rows.length; i++) { 
     // here we create a new array from the worksheet, as we need a 0 index based array. 
     // the worksheet values actually begins at element 1. We will splice to dump the undefined element at index 0. 
     // This will allow the batch promises to work correctly... otherwise everything will be offset by 1 
     var arrValues = Array.from(worksheet.getRow(i).values); 
     arrValues.splice(0, 1); 

     // these queries are upsert. Inserts will occur first, however if they error on the constraint, an update will occur instead. 
     insertStatements.push(t.one('insert into rq_data' + 
            '(col1, col2, col3) ' + 
            'values($1, $2, $3) ' + 
            'ON CONFLICT ON CONSTRAINT key_constraint DO UPDATE SET ' + 
            '(prodname) = ' + 
            '($3) RETURNING autokey', 
            arrValues)); 
     } 

     return t.batch(insertStatements); 
    }) 
    // this two below can be removed... 
    .then(function (data) { 
     return new Promise((resolve, reject) => { 
      console.log('Success:', 'Inserted/Updated ' + data.length + ' records'); 
      resolve(); 
     }); 
    }) 
    .catch(function (error) { 
     return new Promise((resolve, reject) => { 
     console.log('ERROR:', error.message || error); 
     reject(); 
     }); 
    }); 

} 

私はあなたのスニペットを書き直します

var Promise = require('promise'); 

私は自分のコードをテストしていませんが、いくつかのタイプミスのエラーが含ま可能性があります。

+0

データシートを扱う重要なアイデアの1つは、Node.jsメモリのオーバーロードを避けることです。すべてのワークシートをメモリに積み重ねるべきではありません。それらを1つずつ読み込んで処理する必要があります。 –

+0

@ vitaly-tあなたが正しいと私のコードはすべて約束の約束です...編集することができます。一つのアプローチは、ワークシートのファイル名をループし、reduceコールバックの中に対応するものをロードすることです。 – Gab

+0

の要件が変更され、単一のワークシートに対してのみこれを実行する必要があります。ループする呼び出しを削除することができます。私はこの論理のいくつかを適応させました!ありがとうございました! – dvsoukup

関連する問題