问题: 我有一个棘手的情况,我递归地遍历文件和目录,当文件符合特定条件时,我使用Node的readLine(异步函数)读取该文件的第一行。读取该行并将条目推入变量(例如depTree)。由于我的某些代码是异步的,因此无法同步获取depTree的值。
代码:
const fs = require('fs');
const readline = require('readline');
const path = './mycoolpath/';
const depTree = [];
const imports = file => {
const readLines = readline.createInterface({
input: fs.createReadStream(file),
crlfDelay: Infinity
});
// read each line, and push line to depTree if it passes my regex criteria
readLines.on('line', (line) => {
if (/lineMatchesMyregex/.test(line)) {
depTree.push(line)
}
});
}
const recursiveSearch = path => {
const files = fs.readdirSync(path);
for (var i in files) {
var file = path + '/' + files[i];
var stats = fs.statSync(file);
if (stats.isFile()) {
imports(file);
}
else if (stats.isDirectory()) {
recursiveSearch(file);
}
}
};
recursiveSearch(path);
//// embaressing setTimeout
// setTimeout(() => {
// console.log(depTree)
// }, 1000)
尝试:
我必须使用setTimeout,并且我确定有更好的方法,我已经修改了回调和Promise,但无济于事。我将不胜感激。
答案 0 :(得分:1)
您可以构建一个promise数组而不是一个行数组,然后使用Promise.all
等待它们全部解决(或其中任何一个拒绝)。请参阅下面的***
:
const fs = require('fs');
const readline = require('readline');
const path = './mycoolpath/';
const depTreePromises = []; // ***
const imports = file => {
const readLines = readline.createInterface({
input: fs.createReadStream(file),
crlfDelay: Infinity
});
// read each line, and push line to depTree if it passes my regex criteria
// *** Remember a promise
depTreePromises.push(new Promise((resolve, reject) => {
readLines.on('line', (line) => {
if (/* can this fail? */) {
reject(/*...*/);
} else {
resolve(/lineMatchesMyregex/.test(line) ? line : null);
}
// Side note: `destroy` the stream here? Since there's no need
// for more lines?
});
}));
}
const recursiveSearch = path => {
const files = fs.readdirSync(path);
for (var i in files) {
var file = path + '/' + files[i];
var stats = fs.statSync(file);
if (stats.isFile()) {
imports(file);
}
else if (stats.isDirectory()) {
recursiveSearch(file);
}
}
};
recursiveSearch(path);
// *** Wait for all, use result
Promise.all(depTreePromises)
.then(depTree => depTree.filter(n => n !== null)) // Remove the ones that didn't match (can be just `n => n` if blank lines aren't a match for your regex
.then(depTree => {
console.log(depTree);
})
.catch(error => {
// do something with the error
});
您可能还会考虑使用async
函数,尽管如果在上面天真地使用它们,它们会使代码比当前的更具串行性(当前许多行读取是并行的,这很好)。
答案 1 :(得分:1)
如果在Node.js中使用async/await
关键字和Promise,则可以按以下方式解决此问题:
const fs = require('fs');
const readline = require('readline');
const path = './mycoolpath/';
const depTree = [];
const imports = file => {
return new Promise((resolve, reject) => {
const readLines = readline.createInterface({
input: fs.createReadStream(file),
crlfDelay: Infinity
});
// read each line, and push line to depTree if it passes my regex criteria
readLines.on('line', (line) => {
if (/lineMatchesMyregex/.test(line)) {
depTree.push(line)
}
});
// once done reading all the lines, resolve the promise
readLines.on('close', () => {
resolve();
})
});
}
const recursiveSearch = async (path) => {
const files = fs.readdirSync(path);
for (var i in files) {
var file = path + '/' + files[i];
var stats = fs.statSync(file);
if (stats.isFile()) {
await imports(file);
} else if (stats.isDirectory()) {
await recursiveSearch(file);
}
}
};
//// embaressing setTimeout
setTimeout(async () => {
await recursiveSearch(path);
console.log(depTree)
}, 1000)
// or even better, to avoid too long or too short timeout
recursiveSearch(path)
.then(() => {
console.log(depTree)
})
答案 2 :(得分:0)
假设:OP在读取文件方面没有问题,但是在a / sync方面。 我已经使用“ BUGUTILS.blocker(3)”来模仿读取的同步文件。
results.forEach(result=>{
console.log("\t",result);
})
可以代替“ finish(...)”或其他任何东西
"use strict";
const results = [];
const blockingPromise = ()=>{
return new Promise((resolve,reject)=>{
BUGUTILS.blocker(3);
if(Math.random()<.5){
return reject('Less than 50%');
}
return resolve('Greater than or equal to 50%');
})
}
const recurseBlockingPromise= (count)=>{
if(!count || count==0){
console.log('all done')
}else{
recurseBlockingPromise(--count);
//BUGUTILS.blocker(3);
blockingPromise()
.then(r=>{
results.push(r)
console.log('promised resolved',r);
}).catch(e=>{
results.push(e)
console.log('promised rejected',e);
})
}
}
const BUGUTILS = require('./debug-utils');
console.log('Before')
let p = new Promise((resolve,reject)=>{
recurseBlockingPromise(3);
return resolve('All Good')
}).then(r=>{
console.log('finished no error');
results.forEach(result=>{
console.log("\t",result);
})
//console.log("\t" ,results.join("\n\t"),"\t");
}).catch(e=>{
console.log('Finsished with error',e);
})
console.log('after')
如果运行上面的代码将“ BUGUTILS.blocker(3)”替换为同步调用,则会看到事件链。在所有异步调用完成之前执行“ After”输出语句-但是直到所有的Promise都解决之前,脚本不会完成。