Рефакторинг кода с обещаниями прочитать файлы и преобразовать их в json - PullRequest
0 голосов
/ 22 февраля 2020

Я пытаюсь сделать следующее: прочитать содержимое каталога, чтобы найти все файлы. xml (я использую glob , но я хотел бы использовать что-то вроде fs.readdir из fs), затем я хочу прочитать каждый файл, используя fs.readFile, а затем хочу преобразовать файл xml в JSON объекты. Для этой цели я использую xml2 json.

Как только у меня появятся объекты json, я бы хотел перебрать каждый из них, чтобы получить из него одно свойство и pu sh это к массиву. В конце концов весь код помещается в функцию, которая записывает содержимое массива (после завершения). Этот код в настоящее время работает нормально, но я попадаю в знаменитый ад обратного вызова.

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()

Однако я бы хотел перейти к более чистому и элегантному решению (используя обещания). Я читал сообщество и нашел некоторые идеи в некоторых похожих постах здесь или здесь .

Мне бы хотелось узнать ваше мнение о том, как Я должен действовать в подобных ситуациях. Должен ли я go для syn c версии readFile вместо этого? Должен ли я использовать promisifyAll для рефакторинга моего кода и использования обещаний везде? Если да, не могли бы вы пояснить, как должен выглядеть мой код?

Я также узнал, что существует версия fs , основанная на обещаниях , начиная с узла v10.0.0 и далее. Должен ли я go для этого варианта? Если так, то как мне поступить с парсером.в Json ()? Я также видел, что есть еще одна основанная на обещаниях версия под названием xml -to- json -promise .

Я очень ценю ваше понимание этого, поскольку я не очень хорошо знаком с обещаниями, когда задействованы несколько асинхронных операций и циклов, поэтому я в итоге получаю грязные решения для подобных ситуаций.

С уважением, J

1 Ответ

1 голос
/ 23 февраля 2020

Я бы действительно предложил вам использовать обещанную версию glob и fs, а затем использовать async, await и Promise.all, чтобы все это сделать.

NB : Я не вижу логи c о проверке 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...
});

Как в в комментариях, которые вы пишете, у вас есть проблемы с доступом к 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...
});
...