【问题标题】:Refactor code with promises to read files and convert them to json使用承诺重构代码以读取文件并将它们转换为 json
【发布时间】:2020-06-06 21:16:27
【问题描述】:

我正在尝试执行以下操作:读取目录的内容以查找所有 .xml 文件(我使用的是glob,但我想使用 fs 中的 fs.readdir 之类的东西),然后我想使用 fs.readFile 读取每个文件,然后我想将 xml 文件转换为 JSON 对象。为此,我使用xml2json

一旦我有了 json 对象,我想迭代它们中的每一个以从中获取一个属性并将其推送到数组中。最终,所有代码都包装在一个记录数组内容的函数中(一旦完成)。这段代码目前运行良好,但我正在进入著名的回调地狱。

const fs = require('fs');
const glob = require('glob');
const parser = require('xml2json');
let connectors = [] 


function getNames(){
glob(__dirname + '/configs/*.xml', {}, (err, files) => {
     for (let j=0; j < files.length; j++) {
          fs.readFile( files[j], function(err, data) {
             try {
                   let json = parser.toJson(data, {object: true, alternateTextNode:true, sanitize:true})               
                   for (let i=0; i< json.properties.length; i++){
                     connectors.push(json.properties[i].name)
                   if (connectors.length === files.length){return console.log(connectors)}
                   }
              }
              catch(e){
                   console.log(e)
              }
       });
     }
 })
}
getNames()

但是,我想转向一个更干净、更优雅的解决方案(使用 Promise)。我一直在阅读社区,并在herehere 的一些类似帖子中找到了一些想法。

我想听听您对我应该如何处理这种情况的意见。我应该改用 readFile 的同步版本吗?我应该使用promisifyAll 重构我的代码并在任何地方使用promise 吗?如果是这样,您能否详细说明我的代码应该是什么样的?

我还了解到从节点 v10.0.0 开始有一个 promises based version of fs。我应该选择那个选项吗?如果是这样,我应该如何处理 parser.toJson() 部分。我还看到还有另一个基于 Promise 的版本,称为 xml-to-json-promise

非常感谢您对此的见解,因为当涉及多个异步操作和循环时,我对 Promise 不是很熟悉,因此我最终会为这种情况提供肮脏的解决方案。

问候, J

【问题讨论】:

  • connectors.length === files.length背后的逻辑是什么?一个和另一个有什么关系?
  • @trincot 这是一种了解连接器数组何时已完全填充的方法。当要填充的数组长度(连接器)等于文件数时。然后我返回控制台日志,并在调用函数时填充数组。
  • 我不明白:每个文件可以有多个属性,那么文件数与属性总数有何关系?另外,请注意return 不会中断处理,仍然可以执行更多readFile 回调。
  • 这个想法是文件是一个由 x 个文件名组成的数组,旨在由 fs.ReadFile 读取。该 if 语句仅用于检查连接器数组是否已完全填充(它的元素数量与文件数量相同)。但现在我再想一想,你是对的,因为每个文件可以有多个属性。我怎么知道数组何时被填充?感谢您指出这一点

标签: node.js asynchronous promise fs bluebird


【解决方案1】:

我确实建议你使用globfs 的promise 版本,然后使用asyncawaitPromise.all 来完成这一切。

注意:我看不到有关connectors.length === files.length 检查的逻辑,因为理论上连接器(属性)的数量可能大于文件的数量。我假设你想收集他们的所有,不管他们的数量。

以下是代码的外观(未经测试):

const fs = require('fs').promises; // Promise-version (node 10+)
const glob = require('glob-promise'); // Promise-version
const parser = require('xml2json');

async function getNames() {
    let files = await glob(__dirname + '/configs/*.xml');
    let promises = files.map(fileName => fs.readFile(fileName).then(data =>
        parser.toJson(data, {object: true, alternateTextNode:true, sanitize:true})
              .properties.map(prop => prop.name)
    ));
    return (await Promise.all(promises)).flat();
}

getNames().then(connectors => {
    // rest of your processing that needs access to connectors...
});

正如您在 cmets 中所写的那样,您在访问 properties.map 时遇到问题,执行一些验证,并跳过不存在 properties 的情况:

const fs = require('fs').promises; // Promise-version (node 10+)
const glob = require('glob-promise'); // Promise-version
const parser = require('xml2json');

async function getNames() {
    let files = await glob(__dirname + '/configs/*.xml');
    let promises = files.map(fileName => fs.readFile(fileName).then(data =>
        (parser.toJson(data, {object: true, alternateTextNode:true, sanitize:true})
              .properties || []).map(prop => prop.name)
    ));
    return (await Promise.all(promises)).flat();
}

getNames().then(connectors => {
    // rest of your processing that needs access to connectors...
});

【讨论】:

  • 这是什么.flat()?哦……这是 Array.smoosh!不错!
  • 它创建一个二维数组(连接器块)的一维数组。如果没有支持,也可以通过[].concat(...await Promise.all(promises))来完成。
  • @trincot 这个想法很棒,而且似乎是前进的方向。但是,我遇到一个错误,提示 (node:41475) UnhandledPromiseRejectionWarning: TypeError: parser.toJson(...).properties.map is not a function。但是,如果我将 prop=> prop.name 替换为 prop=> console.log(prop.name) 它会记录我想要的所有值。可能是什么问题?
  • 这意味着您遇到toJson() 返回一个没有properties 属性的对象的情况。所以你可能应该首先将toJson() 的结果保存在一个变量中,然后检查它是否有properties,然后决定在任何一种情况下你想要发生什么......
  • 查看补充以了解如何处理丢失的properties
猜你喜欢
  • 1970-01-01
  • 2021-01-07
  • 2014-01-27
  • 2021-10-14
  • 2021-11-25
  • 1970-01-01
  • 2019-02-23
  • 2017-05-03
  • 1970-01-01
相关资源
最近更新 更多