JavaScript递归函数中Promise的正确使用:实现目录遍历后输出完成提示
修正递归目录遍历Promise的resolve位置,实现预期输出顺序
你的问题核心是没有等待所有异步遍历操作完成就提前resolve了Promise。原代码里,只要遇到第一个文件(app.js)就调用resolve,这会直接触发.then()里的completed输出,而此时子目录的遍历还在后台异步执行,所以后续的temp1.js、temp2.js会在completed之后才打印出来。
要实现所有文件输出完成后再打印completed,我们需要:
- 收集所有文件/子目录处理的异步任务(Promise)
- 等待所有任务完成后,再统一resolve整个
readDirectory的Promise
修正后的代码(推荐使用async/await简化写法)
const fs = require('fs').promises; const path = require('path'); let readDirectory = async function(dirname) { const files = await fs.readdir(dirname); // 收集每个文件的处理任务为Promise const tasks = files.map(async (file) => { const filePath = path.join(dirname, file); const stats = await fs.stat(filePath); if (stats.isDirectory()) { // 递归遍历子目录,等待子目录处理完成 await readDirectory(filePath); } else { // 打印当前文件名 console.log(file); } }); // 等待当前目录下所有任务(文件+子目录)执行完成 await Promise.all(tasks); }; // 调用并处理完成后的逻辑 readDirectory(sampledir) .then(() => console.log('completed')) .catch(err => console.error('遍历出错:', err));
关键改动说明
- 改用
fs.promises:避免嵌套回调地狱,代码结构更清晰易读。 - 用
map替代forEach:forEach无法等待异步操作结束,map可以将每个文件的处理转化为Promise并存入数组,方便后续统一等待。 Promise.all统一等待:确保当前目录下的所有文件、子目录都遍历完成后,才会让整个readDirectory的Promise进入resolved状态。- 移除过早的
resolve:原代码中单个文件处理时就调用resolve的逻辑被移除,改为等待所有任务完成后,由async函数自动返回resolved的Promise。
如果你坚持使用原始的Promise回调写法,也可以这样调整:
const fs = require('fs'); const path = require('path'); let readDirectory = function(dirname){ return new Promise((resolve,reject)=>{ fs.readdir(dirname,(err,files)=>{ if(err) reject(err); // 收集所有文件处理的Promise const promises = files.map(file=>{ return new Promise((innerResolve)=>{ const filePath = path.join(dirname, file); fs.stat(filePath,(err,stats)=>{ if(stats.isDirectory()){ // 递归遍历子目录,等待其完成后再标记当前任务结束 readDirectory(filePath).then(innerResolve); }else{ console.log(file); innerResolve(); } }) }) }); // 所有任务完成后,再resolve外层Promise Promise.all(promises).then(resolve).catch(reject); }) }) } readDirectory(sampledir).then(()=>console.log('completed')).catch(err=>console.error(err));
修改后,输出顺序会完全符合你的预期:
app.js temp1.js temp2.js completed
内容的提问来源于stack exchange,提问作者Krishna Chaitanya
相关产品推荐
相关产品推荐

