首页 > 解决方案 > NodeJS CSVReader - 带有 csv-parse 的 createReadStream 返回空数组

问题描述

我有一个 CSV 阅读器类,它带有两个参数(文件路径和模型)。文件路径是 .csv 文件的路径,模型是构建 .csv 文件的模型。数据将存储在输出数组中。它有一个问题,因为当我返回数组时,它是空的。但是当我控制台记录数组时,它里面有数据。有人能帮我吗?

索引.js

const parse = require('csv-parse')
const fs = require('fs');
const output = [];

class CSVReader{
    static GetRecord(filePath, model){
        fs.createReadStream(filePath)
            .pipe(parse({columns: false, delimiter: ',', trim: true, skip_empty_lines: true}))
            .on('readable', function (){
                let record
                while (record = this.read()){
                    let city = model.create(record)
                    output.push(record)
                }
            })
            .on('end', function (){
                //console.log(output);
            })
        return output;
    }
}
module.exports = CSVReader;

我用 Jest 测试了文件,但它有一个问题,正如预期的那样是 6,但我收到了 []

索引.test.js

const CSVReader = require('../src/Index');
const City = require('../src/Models/City')
test('Can Read CSV File', () => {
    let filePath  = 'data/worldcities.csv';
    let records = CSVReader.GetRecord(filePath, City);
    expect(records.length).toBe(6);
});

标签: javascriptjestjs

解决方案


tl;博士:

这是一个异步调用,因此您不能只返回响应并期望它起作用。您需要使用 Promise API 和异步函数。

是什么让这个异步?

所有 Node.js fsAPI 都是异步的(不包括fs.*Sync函数)。

我如何使用 Promise?

Promise您可以在函数顶部返回 a ,然后传递回调:

return new Promise((resolve, reject) => { /* callback */ });

修复代码

// all of this is fine
const parse = require('csv-parse')
const fs = require('fs');
// remove the const output = []; as this will cause problems

class CSVReader{
    // this needs to be async
    static async GetRecord(filePath, model){
        // return a promise
        return new Promise((resolve, reject) => {
            // assign output here (https://stackoverflow.com/a/66402114/14133230)
            const output = [];
            fs.createReadStream(filePath)
                .pipe(parse({columns: false, delimiter: ',', trim: true, skip_empty_lines: true}))
                .on('readable', function (){
                    let record
                    while (record = this.read()){
                        let city = model.create(record)
                        output.push(record)
                    }
                    // you may need to call WriteStream#close() here
                })
                .on('end', function (){
                    // output is available here
                    // resolve the promise
                    resolve(output);
                })
        });
    }
}
module.exports = CSVReader;

使用新的基于 Promise 的函数

const CSVReader = require('../src/Index');
const City = require('../src/Models/City')
test('Can Read CSV File', () => {
    let filePath  = 'data/worldcities.csv';
    let records = CSVReader.GetRecord(filePath, City); // type Promise
    records.then((response) => { // when promise fills
        expect(response.length).toBe(6);
    });
});

推荐阅读