recursive async to promises or callback
问题:
我有一个棘手的情况,我递归地遍历文件和目录,并且当文件符合特定条件时,我使用Node的readLine(异步函数)读取该文件的第一行。 读取该行并将条目推入变量(例如depTree)。 由于我的某些代码是异步的,因此无法同步获取depTree的值。
码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | 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但无济于事。 我将不胜感激。
如果在Node.js中使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | 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数组而不是一个行数组,然后使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | 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 }); |
您可能还会研究
假设:OP在读取文件方面没有问题,但是在a / sync方面。
我已使用" BUGUTILS.blocker(3)"来模拟读取的同步文件。
1 2 3 | results.forEach(result=>{ console.log("\\t",result); }) |
可以代替'finish(...)'或其他任何东西
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | "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("\ \\t"),"\\t"); }).catch(e=>{ console.log('Finsished with error',e); }) console.log('after') |
如果运行上面的代码将" BUGUTILS.blocker(3)"替换为同步调用,则会看到事件链。在所有异步调用完成之前,将执行" After"输出语句-但是直到所有的Promise都解决后,脚本才会完成。