You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 11:05:31