将Node.js中基于async/await的代码转换为Promise链式调用
改造Node.js扫描程序为Promise链式调用结构
核心前提
你熟悉Python的async/await,其实Node.js里的async函数本身就会返回一个Promise——这是改造的关键。只要让每个流程函数返回需要传递的结果,就能自然实现.then()的链式调用,替代原来的回调模式。
修改后的完整代码
const chalk = require('chalk'); const ProgressBar = require('progress'); const fs = require('fs'); const path = require('path'); async function* walk(dir) { for await (const d of await fs.promises.opendir(dir)) { const entry = path.join(dir, d.name); if (d.isDirectory()) yield* await walk(entry); else if (d.isFile()) yield entry; } } // 1. 改造scan函数:接受目录参数,返回Promise(自动由async函数实现) async function scan(dir) { const docs = []; for await (const p of walk(dir)) { if (p.endsWith('.md')) { console.log(p); docs.push(p); } } docs.sort(); return docs; // 返回的内容会成为Promise resolve的值,供后续.then接收 } // 2. 改造inspect函数:处理后返回docs,保证链式传递 async function inspect(docs) { const bar = new ProgressBar(':bar', { total: docs.length }); let index = 0; // 把for (f in docs)改成for...of,避免遍历索引的坑 for (const file of docs) { if (index === 0) { console.log(chalk.green('starting...')); } bar.tick(); // 在这里执行你的文件处理逻辑,可直接修改docs数组 index++; if (bar.complete) { console.log(chalk.green('done.')); } } return docs; // 返回处理后的docs,传递给下一个环节 } // 示例generate函数:接受docs和目标路径参数 async function generate(docs, targetPath) { // 这里实现读取文件、按内容排序、生成目录的逻辑 // 示例:将docs列表写入目标文件 await fs.promises.writeFile(targetPath, JSON.stringify(docs, null, 2)); console.log(chalk.blue(`目录已生成到 ${targetPath}`)); return docs; // 可选:继续传递结果给后续流程 } // 错误处理函数 function printError(err) { console.error(chalk.red(`出错了:${err.message}`)); } // 3. 链式调用写法 scan('docs') .then(inspect) .then(docs => generate(docs, '/path/to/target/file/')) // 用箭头函数传递额外参数 .catch(printError); // 统一捕获整个链式流程中的错误
关键改动说明
scan函数的改造:
- 去掉了回调参数
cb,换成接收扫描目录dir - 最后
return docs:async函数会自动把这个值包装成resolved状态的Promise,后续.then()就能拿到这个docs数组
- 去掉了回调参数
inspect函数的改造:
- 保留接收docs参数,但最后要
return docs(或者修改后的docs),这样下一个.then()才能拿到处理后的结果 - 把
for (f in docs)改成for...of,避免遍历数组索引的问题(原来的写法会拿到0、1、2这类索引值,而非文件名)
- 保留接收docs参数,但最后要
链式调用的参数传递:
- 如果后续函数需要额外参数(比如
generate的目标路径),不能直接写.then(generate, '/path/')(因为.then()的第二个参数是错误回调),要用箭头函数包裹:.then(docs => generate(docs, '/path/'))
- 如果后续函数需要额外参数(比如
错误处理:
- 整个链式流程中的任何错误(比如扫描目录失败、文件写入失败)都会被最后的
.catch(printError)捕获,比回调模式的错误处理更集中、清晰
- 整个链式流程中的任何错误(比如扫描目录失败、文件写入失败)都会被最后的
和Python async/await的对应关系
你可以把.then(a).then(b)理解成Python里的:
result = await scan() result = await inspect(result) await generate(result, '/path/')
两者本质都是异步流程的线性执行,只是Node.js提供了Promise链式的写法,和async/await是互补的(你也可以在链式里混用await)。
内容的提问来源于stack exchange,提问作者ZioByte
相关产品推荐
相关产品推荐

