如何使用 csv-parse 避免等待...

Posted

技术标签:

【中文标题】如何使用 csv-parse 避免等待...【英文标题】:How to avoid for await...of with csv-parse 【发布时间】:2022-01-21 16:44:38 【问题描述】:

我希望接受有关此问题的教育,因为我花了几天时间试图自己解决它,但无济于事。

我正在使用 csv-parse 解析 CSV 文件。 我正在使用 ESLint 作为我的 Linter 我正在为 ESLint 使用 Airbnb javascript Style Guide 插件 我正在使用 NodeJS 在后端运行它

我的功能是:

const  parse  = require('csv-parse');
const fs = require('fs');
const csvFile = 'myCsvFile.csv';

async function parseCsv(csvFile) 
  const records = [];
  const parser = fs.createReadStream(csvFile).pipe(parse( delimiter: ',', columns: true ));
  for await (const record of parser) 
    records.push(record);
  
  return records;

该功能运行良好,但是我正在尝试遵守 Airbnb 的样式指南,它不喜欢 for await...of 循环,因为它违反了 no-restricted-syntax

我很好奇是否有更好的方法来编写此代码以符合 Airbnb 的样式指南,或者如果这是可以忽略违规的情况之一?

【问题讨论】:

嗯,你所链接的任何Airbnb推理是否引起了你的共鸣? 为什么?这执行了我们的不可变规则。处理返回值的纯函数比副作用更容易推理。这似乎不适用于您的情况。 @Bergi,好问题。不,它没有引起我的共鸣,这就是我问的原因。我才刚刚踏上这段旅程的几年,有时我需要帮助才能透过树木看到森林。看似简单的事情,我仍然怀念。 @JeremyM 然后我建议不要使用该样式指南(或至少不要使用该规则)。 Imo,airbnb 有点误导,经常阻止你使用现代语法。 @EmielZuurbier 在某种程度上,确实如此,records.push(record) 是一个副作用。问题是目前节点流(或异步迭代器)上没有帮助方法可以缓解这种情况 - 但是使用iterator helpers proposal,您可以将所有这些简化为const records = await parser.toArray() 【参考方案1】:

风格指南说:

11.2 暂时不要使用生成器。 为什么?它们不能很好地转换为 ES5。

幸运的是,如果您使用的是最新的 NodeJS 版本,则无需向下转换,并且可以使用引擎的原生支持。对于浏览器,此建议也很快过时了。

【讨论】:

【参考方案2】:

根据答案中给出的建议,我将忽略Airbnb Style Guide 并使用Async iterator 方法。

最终代码:

const  parse  = require('csv-parse');
const fs = require('fs');
const path = require('path');
const debug = require('debug')('app:csv:service');
const chalk = require('chalk');

async function parseCsv(csvFile) 
  try 
    const records = [];
    const stream = fs.createReadStream(csvFile);
    const parser = stream.pipe(parse( delimiter: ',', columns: true ));
    // eslint-disable-next-line no-restricted-syntax
    for await (const record of parser) 
      records.push(record);
    
    return records;
   catch (error) 
    debug(`$chalk.red('Failed') to parse CSV`);
    debug(`$chalk.red('ERROR:') $error`);
    throw error;
  

可能是时候寻找新的样式指南来遵循了。感谢 num8er 提供代码建议(我采纳了您的一个想法,使我的代码更具可读性)。

【讨论】:

【参考方案3】:

使用事件结束返回承诺怎么样?

const  parse  = require('csv-parse');
const fs = require('fs');
const csvFile = 'myCsvFile.csv';

async function parseCsv(csvFile) 
  return new Promise((resolve) => 
    const records = [];
    const stream = fs.createReadStream(csvFile);
    const parser = stream.pipe(parse( delimiter: ',', columns: true ));
    
    parser.on('readable', () => 
      while (record = parser.read()) 
        records.push(record);
      
    );

    let ended = false;
    const end = (error) => 
      if (error) 
        console.error(error.message);
      

      if (!ended) 
        ended = true;
        resolve(records);
      
    ;

    parser.on('error', end);
    parser.on('end', end);
  );

如果您有节点 15+,请尝试 stream/promises 示例:

const  parse  = require('csv-parse');
const fs = require('fs');
const  finished  = require('stream/promises');
const csvFile = 'myCsvFile.csv';

async function parseCsv(csvFile) 
    const records = [];
    const stream = fs.createReadStream(csvFile);
    const parser = stream.pipe(parse( delimiter: ',', columns: true ));

    parser.on('readable', () => 
      let record;
      while ((record = parser.read()) !== null) 
        records.push(record);
      
    );

    await finished(parser);

    return records;

【讨论】:

如果将 3 行 for 循环替换为 20 行回调和手动承诺解析使代码兼容,我真的会质疑样式指南... @JonasWilms 我试图让代码没有异步/等待,我认为这是让它更兼容旧的 lts 东西的原因:) 我能够让它作为一个 Promise 工作,但我同意@Jonas Wilms,它需要更多的代码才能让它工作。我开始质疑风格指南。不过这会动摇我的世界?。 3 年前,我开始了这段旅程,强迫自己按照 Airbnb 风格指南学习。对我来说,这几乎是一种宗教。 @JeremyM 你可以使用on_record 并简化我的代码,csv.js.org/parse/options/on_record @JeremyM 如果您使用的是节点 15+,那么请检查带有流/承诺的示例,我已经更新了我的答案

以上是关于如何使用 csv-parse 避免等待...的主要内容,如果未能解决你的问题,请参考以下文章

在expressJS中如何创建一个缓存,使多个请求等待相同的promise [重复]

使用改造向请求添加标头时如何避免在主线程上等待?

如何避免锁定等待超时超出异常。?

如何使python等待对象

当答案== true时如何使void不返回[关闭]

C#如何使同步方法等待事件触发?