如何正确终止Node.js readline promise的question方法?
使用node:readline/promises处理SIGINT/Ctrl+D导致的未解决顶级await问题
问题场景
在Node.js v22.2.0的ES模块环境中,使用node:readline/promises的rl.question()等待用户输入时,若用户通过SIGINT(Ctrl+C)或Ctrl+D终止操作,会触发「未解决顶级await」警告——因为rl.question()返回的Promise未被妥善拒绝或完成。
问题代码
import * as readline from 'node:readline/promises'; const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); const answer = await rl.question('>>> ');
触发的警告信息
Warning: Detected unsettled top-level await at file:///foo/bar/test.js:xx const answer = await rl.question('>>> ');
解决方案:妥善处理中断与关闭事件
通过Promise.race让用户输入Promise和中断处理Promise竞争,在触发中断或流关闭时主动拒绝Promise,确保顶级await能被正确处理。
import * as readline from 'node:readline/promises'; const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); // 封装中断处理逻辑为Promise const handleInterruption = new Promise((_, reject) => { // 监听SIGINT信号(Ctrl+C) process.once('SIGINT', () => { console.log('\n用户通过Ctrl+C中断输入'); rl.close(); reject(new Error('输入操作被中断')); }); // 监听readline接口的close事件(比如Ctrl+D触发) rl.once('close', () => { console.log('输入流已关闭(Ctrl+D)'); reject(new Error('输入流终止')); }); }); try { // 同时等待用户输入或中断事件 const answer = await Promise.race([rl.question('>>> '), handleInterruption]); console.log(`你输入的内容是: ${answer}`); } catch (err) { console.error('处理提示:', err.message); } finally { // 确保readline接口被关闭 if (!rl.closed) { rl.close(); } }
思路说明
这个方案和你提供的非Promise版readline思路一致:通过监听中断信号和流关闭事件,主动终止未完成的Promise。区别在于利用Promise.race简化了逻辑,无需手动维护reject函数的引用,同时统一了SIGINT和Ctrl+D两种场景的处理。
非Promise版参考代码(你提供的实现)
import * as readline from 'node:readline'; const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); let rej = () => {}; rl.on('close', () => { console.log('closing'); rej(); }); const answer = await new Promise((r, j) => { rej = j; rl.question('>>> ', r); }).catch(() => console.error('interrupted'));
内容的提问来源于stack exchange,提问作者W. Smith
相关产品推荐
相关产品推荐

