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

Node.js中readline按键监听器导致程序无法自动退出的问题

Node.js TUI应用监听单次按键后进程无法自动退出

我正尝试为Node.js TUI应用编写一个可await的异步函数,要求无需按回车即可监听单次键盘按键,并返回按键信息,且不使用任何NPM包。

我的函数代码如下:

export async function inkey_promise() {
    console.log('Press any key...');

    return new Promise((resolve) => {
        readline.emitKeypressEvents(process.stdin);
        process.stdin.setRawMode(true);
        const listener = (str, readline_key) => {
            process.stdin.setRawMode(false);
            process.stdin.resume();
            console.log(`RETURNING: `, readline_key);
            return resolve(readline_key);
        };
        process.stdin.once('keypress', listener);
    });
}

调用方式:

const key_info = await inkey_promise();

问题:按下按键后,Promise正常resolve,后续代码也能正常执行,但当程序无任务可执行时,会一直运行无法自动退出,除非手动终止进程。我不想显式调用process.exit(),因为按键后程序通常还有任务执行,但无任务时应正常退出。似乎需要将process/stdin/键盘完全恢复到默认状态?


解决方案

问题根源是你没有将stdin完全恢复到启动时的默认状态,导致进程持续监听stdin输入,无法自动退出。以下是修正后的函数:

import readline from 'readline'; // 确保导入readline模块

export async function inkey_promise() {
    console.log('Press any key...');

    return new Promise((resolve) => {
        readline.emitKeypressEvents(process.stdin);
        process.stdin.setRawMode(true);
        process.stdin.resume(); // 临时恢复stdin以接收按键

        const listener = (str, readline_key) => {
            // 恢复默认终端模式
            process.stdin.setRawMode(false);
            // 暂停stdin,回到Node.js启动时的默认状态
            process.stdin.pause();
            // 显式移除监听(配合once双重保险)
            process.stdin.off('keypress', listener);
            // 清理readline关联的终端状态
            readline.clearLine(process.stdin, 0);
            
            console.log(`RETURNING: `, readline_key);
            resolve(readline_key);
        };
        process.stdin.once('keypress', listener);
    });
}

关键修正点:

  • 调用process.stdin.pause():Node.js启动时stdin默认处于暂停状态,之前只调用了resume()但未恢复,导致进程持续监听stdin无法退出。
  • 添加process.stdin.off('keypress', listener):虽然用了once,显式移除监听可避免潜在的残留绑定问题。
  • 使用readline.clearLine():清理readline遗留的终端状态,确保环境完全重置。

修改后,当程序无后续任务时,进程会因stdin不再被监听而正常退出,无需手动调用process.exit()。

内容的提问来源于stack exchange,提问作者LaVache

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 05:51:19