递归walkDir函数通过回调更新外部变量的实现问题
递归walkDir函数通过回调更新外部变量的实现问题
我看了你写的递归遍历目录的代码,这里面有好几个关键问题导致最后输出undefined undefined,咱们一步步把这些问题理清楚,再给出能正常工作的实现:
先说说原代码里的核心问题
- 异步函数调用没加await:
walkDir是async函数,它返回的是一个Promise,你直接解构它的返回值肯定拿不到结果,得用await或者.then()来处理。 - 回调函数的逻辑完全混乱:你定义的
cb函数里每次都会新建一个stats对象,而且返回了一个嵌套的匿名函数,但walkDir里调用cb(entry, file)时,file变量根本没定义,也没用到你返回的那个匿名函数,等于回调完全没起作用。 - 文件路径错误:你在获取文件状态的时候用了
file变量,但这个变量从来没被赋值过,应该用拼接后的完整文件路径才能正确获取到文件的stats。 - 统计状态没有共享:统计用的
stats对象应该在外部创建,让每次回调都操作同一个对象,而不是每次回调都新建,不然根本没法累计数据。
修正后的完整实现
咱们重新写一遍代码,把这些问题都解决:
import fs from 'node:fs/promises'; import path from 'path'; // 修正后的walkDir:传递完整文件路径给回调 async function walkDir(dir, cb) { const entries = await fs.readdir(dir, { withFileTypes: true }); for (const entry of entries) { const fullPath = path.join(dir, entry.name); if (entry.isDirectory()) { await walkDir(fullPath, cb); } else { // 把完整路径和entry都传给回调 await cb(entry, fullPath); } } } // 主函数里创建共享的统计对象 async function main() { const stats = { numOfJs: 0, sizeOfBiggest: 0 }; // 定义回调函数:直接操作共享的stats对象 const updateStats = async (entry, fullPath) => { if (path.extname(entry.name) === '.js') { stats.numOfJs++; const fileStats = await fs.stat(fullPath); if (fileStats.size > stats.sizeOfBiggest) { stats.sizeOfBiggest = fileStats.size; } } }; // 调用walkDir必须加await await walkDir('.', updateStats); // 现在就能拿到正确的统计结果了 console.log(stats.numOfJs, stats.sizeOfBiggest); } // 执行主函数 main().catch(err => console.error(err));
代码里的关键修正点
- 共享的stats对象:把
stats对象定义在主函数里,让回调直接操作这个对象,这样所有回调都共享同一个统计状态,能正确累计数据。 - 正确传递文件路径:在
walkDir里拼接出文件的完整路径fullPath,并传给回调,这样获取文件状态时才能拿到正确的文件信息。 - 异步函数的正确调用:用
await walkDir(...)等待遍历完成,因为遍历操作是异步的,必须等它完成才能拿到最终的统计结果。 - 简化的回调逻辑:去掉了原代码里多余的嵌套函数,回调直接处理当前文件的统计逻辑,清晰明了。
额外的优化建议
如果你想让这个walkDir更通用,支持不同的统计逻辑,可以把stats对象作为参数传递给回调,或者让回调返回需要更新的状态,但核心都是要保证统计状态是共享的,而不是每次回调都新建。
内容来源于stack exchange
相关产品推荐
相关产品推荐

