ノード.ストリームと約束


私は大きな読書が必要なプロジェクトに取り組んでいます.csv ローカルファイルシステムからのファイルで、データを操作する.ノード.JSにはこれを扱うためのいくつかの大きなツールがあります.すなわち、ストリーム、イベントエミッタ、 readline ネイティブモジュール.しかし、コード例/チュートリアルのすべては、次の3つのカテゴリのうちの1つに分類されました
  • データをコンソールに出力します(便利ではありません)
  • データをファイルに書き込む
  • 受信データを外部配列にプッシュする
  • 外部ライブラリを使う
  • 外部ライブラリを使い始めましたcsv-parser . しかし基本的にはベースノードのラッパです.私が上にリストしたJS技術は、私が以下にリストする私のデータで働く同じ問題を抱えています.私は最終的にそれをアンインストールし、自分の軽量版を書いた.

    背景


    The `readline` module provides an interface for reading data from a Readable stream...one line at a time. from [Node.js Documentaion](https://nodejs.org/docs/latest-v16.x/api/readline.html)

    All streams are instances of EventEmitter. from [Node.js Documentaion](https://nodejs.org/docs/latest-v16.x/api/stream.html)

    ストリームと基本的には、データを使ってイベントを聞くことを意味します.そして.on メソッドEventEmitter コールバックを期待しています.The readline モジュールはあなたにline イベントを聞く.

    液角1


    最初に「外部データへの着信データのプッシュ」アプローチを試みました.
    const incomingData = [];
    
    rl.on('line', data => [
      incomingData.push(data);
    ])
      .on('close', () => {
        // do something with incomingData
      });
    
    あなたが1つのファイルだけを読んでいるならば、この解決は実際に働きます.残念ながら、私はファイルのディレクトリをループして、それぞれを読んで、それからデータで何かをする必要があります.私はカウンタと何かであらゆる種類のものを疲れました、しかし、ループと何が次に起こる必要があったかについてレース状況に走り続けました.それで、本当に私の解決でありません.

    液角2


    このソリューションは、実際に私のローカルコードメンタリングのメンバーから来ましたmeetup . このソリューションは約束を使用します.
    まず、JavaScriptを作成しましたclass フォーマイ.csv ニーズ
    const fs = require('fs');
    const readline = require('readline');
    const path = require('path');
    
    class CSVHelpers {
      constructor () {
        super();
      }
    
      /**
       * @param  {string} filePath
       * @return {promise} Array of row objects. Key: header, value: field value
       */
      read (filePath) {
        return new Promise ((resolve, reject) => {
          try {
            const reader = this._createReadStream(filePath);
            let rows = [];
            let headers = null;
    
            reader.on('line', row => {
              if (headers === null) {
                headers = row.split(',');
              } else {
                const rowArray = row.split(',');
                const rowObject = {};
                rowArray.forEach((item, index) => {
                  rowObject[headers[index]] = item;
                });
    
                rows.push(rowObject);
              }
            })
              .on('close', () => {
                resolve({
                  rows,
                  file: filePath
                });
              });
          } catch (error) {
            reject(error);
          }
        });
      }
    
      /**
       * @param  {type} filePath
       * @return {type} Readline event emitter
       */
      _createReadStream (filePath) {
        const fd = fs.openSync(path.resolve(filePath));
        const fileStream = fs.createReadStream(path.resolve(filePath), {fd});
        return readline.createInterface({
          input: fileStream
        });
      }
    }
    
    module.exports = CSVHelpers;
    
    それから私のコードで
    const csv = new CSVHelpers();
    const dataFiles = fs.readdirSync(<pathToDirectory);
    
    const filePromises = dataFiles.map(file => {
      return csv.read(<pathToFile>);
    });
    
    Promise.all(filePromises)
      .then(values => {
        // do something with the values.
      });
    
    このPromise アプローチは、次のループやコールバックを試みる必要がないことを意味します.

    結論


    私は、これが最善の解決策であるかどうか知りません、しかし、それは私のユースケースのために働いて、私が持っていたレース状況を解決します.あなたが問題を解決するより良い方法があるならば、知らせてください.