重构代码,承诺读取文件并将其转换为 json
Refactor code with promises to read files and convert them to json
我正在尝试执行以下操作:读取目录的内容以查找所有 .xml 文件(我为此目的使用 glob but I'd like to use something like fs.readdir from fs), then I want to read every file using fs.readFile and then I want to convert the xml file to JSON objects. I'm using 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()
但是,我想转向更简洁优雅的解决方案(使用 promises)。我一直在阅读社区,并在一些类似的帖子中找到了一些想法 or here。
对于这种情况我应该如何处理,我想听听您的意见。我应该改用 readFile 的同步版本吗?我应该使用 promisifyAll 来重构我的代码并在任何地方使用 promises 吗?如果是这样,您能否详细说明我的代码应该是什么样子?
我还了解到有一个promises based version of fs from node v10.0.0 onwards. Should I go for that option? If so how should I proceed with the parser.toJson() part. I've also seen that there's another promise-based version called xml-to-json-promise。
非常感谢您对此的见解,因为当涉及多个异步操作和循环时,我对 promises 不是很熟悉,所以我最终得到了针对这种情况的肮脏解决方案。
此致,
J
我确实建议你使用 glob
和 fs
的 promise 版本,然后使用 async
、await
和 Promise.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...
});
如评论中所述,您在访问 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...
});
我正在尝试执行以下操作:读取目录的内容以查找所有 .xml 文件(我为此目的使用 glob but I'd like to use something like fs.readdir from fs), then I want to read every file using fs.readFile and then I want to convert the xml file to JSON objects. I'm using 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()
但是,我想转向更简洁优雅的解决方案(使用 promises)。我一直在阅读社区,并在一些类似的帖子中找到了一些想法
对于这种情况我应该如何处理,我想听听您的意见。我应该改用 readFile 的同步版本吗?我应该使用 promisifyAll 来重构我的代码并在任何地方使用 promises 吗?如果是这样,您能否详细说明我的代码应该是什么样子?
我还了解到有一个promises based version of fs from node v10.0.0 onwards. Should I go for that option? If so how should I proceed with the parser.toJson() part. I've also seen that there's another promise-based version called xml-to-json-promise。
非常感谢您对此的见解,因为当涉及多个异步操作和循环时,我对 promises 不是很熟悉,所以我最终得到了针对这种情况的肮脏解决方案。
此致, J
我确实建议你使用 glob
和 fs
的 promise 版本,然后使用 async
、await
和 Promise.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...
});
如评论中所述,您在访问 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...
});