如何在Node.js的for await readline异步迭代中添加用户提问功能
问题解决思路
核心问题原因
- 你创建
readline实例时设置了terminal: false,该配置会禁用rl.question()的交互提示输出,也会干扰输入流的正常回调 - async生成器在
for await循环执行break时,会自动调用生成器的return()方法终止迭代,你没有在生成器内做资源清理逻辑,导致readline接口持续挂起,看起来像break不生效 - 你的生成器循环没有加数组边界判断,遍历完
file.json的所有数据后会持续读取undefined条目 - 你原来的退出答案里的
quite是拼写错误,正确应为quit
修复后可运行实现
const readline = require('readline'); const { promisify } = require('util'); // 移除错误的terminal: false配置 const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); const promptUserCLI = (q, exitAnswers = [], callback) => { rl.question(q, answer => { if (exitAnswers.includes(answer.toLowerCase())) { rl.close(); return callback(new Error('user exit')); } callback(null, answer); }); }; const promptPromise = promisify(promptUserCLI) const data = require('./file.json'); async function* gen() { let index = 0 // 加finally块,生成器终止(break/报错)时自动关闭readline try { // 加数组边界判断,遍历完所有数据自动终止 while (index < data.length) { const item = data[index] const answer = await promptPromise(`Make '${item.line}' [ [y]es/no/all/exit ]`, ['exit', 'quit']) index += 1 yield { answer, item, index } } } finally { rl.close() } } // 测试逻辑,break可以正常退出 (async () => { try { for await (const item of gen()) { console.log('拿到的返回结果:', item) // 这里break会触发生成器的finally块,关闭rl后正常退出 break } console.log('循环正常终止') } catch (e) { console.log('操作终止:', e.message) } })()
补充说明
- 如果你需要和原生
readline的for await能力结合,不需要重写rl[Symbol.asyncIterator],直接在遍历每行的逻辑里调用promptPromise即可,按你的需求遍历自定义json数据,用独立的async生成器是更简洁的方案 - 可以根据业务需要扩展
gen生成器的逻辑,比如用户输入all的时候直接返回所有剩余条目,不需要逐个提问
内容的提问来源于stack exchange,提问作者Docky-Dockling
相关产品推荐
相关产品推荐

