TypeScript Node.js标准输入脚本阻塞/不等待输入问题求解
问题原因分析
你的代码无限挂起是因为内部的while (userInput === null)是同步死循环——Node.js是单线程事件驱动模型,这个循环会一直霸占事件循环队列,导致data事件的回调根本没机会执行,userInput永远是null,自然卡着不动。移除循环后,脚本会直接往下执行,不等用户输入就走完流程,所以直接结束。
修复方案:用异步方式处理输入
利用Promise封装用户输入逻辑,配合async/await实现“等待输入”的效果,既不会阻塞事件循环,又能保证代码逻辑的顺序性。
修复后的完整代码
import process from 'process'; // 封装异步获取用户输入的函数 function getUserInput(prompt: string): Promise<string> { process.stdout.write(prompt); return new Promise((resolve) => { const standard_in = process.stdin; standard_in.setRawMode(true); standard_in.setEncoding('utf8'); standard_in.resume(); const handleInput = (data: string) => { // 处理有效输入:支持直接按y/n,或按回车确认 const input = data.trim().toLowerCase(); if (input === 'y' || input === 'n' || data === '\n') { standard_in.removeListener('data', handleInput); standard_in.setRawMode(false); // 恢复默认输入模式,避免后续异常 resolve(input === '\n' ? '' : input); } }; standard_in.on('data', handleInput); }); } async function main() { let interactive = true; process.stdout.write("Welcome to CodeWhisperer code generator\n"); do { // 这里替换成你的业务逻辑,生成要展示的命令 process.stdout.write("This is the command you asked for:\n"); process.stdout.write("npm install typescript\n"); // 示例命令 // 等待用户输入 const userInput = await getUserInput("Do you want to use it? (y/n)\n"); console.log(userInput); if (userInput === 'y') { process.stdout.write("Great! Let's go!\n"); interactive = false; } else if (userInput === 'n') { process.stdout.write("Okay, let's try again.\n"); } } while(interactive); // 结束后关闭输入流 process.stdin.pause(); } main().catch(err => console.error(err));
关键修改点
- 异步封装输入逻辑:把用户输入变成返回
Promise的函数,用await等待输入完成,不会阻塞事件循环,让data事件回调有机会执行。 - 避免重复绑定事件:每次获取输入只绑定一次
data监听器,拿到有效输入后立即移除,防止循环中重复绑定导致多次触发。 - 恢复默认输入模式:在获取输入后关闭
raw模式,避免后续输入行为异常(比如默认模式下需要按回车确认输入,raw模式下按任意键都会触发)。
简化版(不需要raw模式)
如果不需要实时响应按键(希望用户输入后按回车确认),可以去掉setRawMode(true),代码更简洁:
import process from 'process'; function getUserInput(prompt: string): Promise<string> { process.stdout.write(prompt); return new Promise((resolve) => { const standard_in = process.stdin; standard_in.setEncoding('utf8'); standard_in.resume(); const handleInput = (data: string) => { const input = data.trim().toLowerCase(); standard_in.removeListener('data', handleInput); standard_in.pause(); resolve(input); }; standard_in.on('data', handleInput); }); } // main函数和之前一致
内容的提问来源于stack exchange,提问作者Matteo Possamai
相关产品推荐
相关产品推荐

