递归异步到承诺或回调



问题: 我有一个棘手的情况,我递归遍历文件和目录,当文件符合特定条件时,我使用 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,我确信有更好的方法,我已经修补了回调和承诺,但无济于事。我将不胜感激任何帮助/见解。

如果在 Node.js 中使用async/await关键字和承诺,则可以按如下方式解决此问题:

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

您可以构建一个承诺数组而不是一行数组,然后使用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函数,尽管如果在上面天真地使用,它们会使代码比现在更串行(目前很多读行是并行的,这很好(。

假设: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("nt"),"t");
}).catch(e=>{
console.log('Finsished with error',e);
}) 
console.log('after')

如果你运行上面的代码,用 'BUGUTILS.blocker(3(' 代替同步调用,你会看到事件链。 "After"输出语句在所有异步调用完成之前执行 - 但脚本在所有承诺解决之前不会完成。

最新更新