Node.js 如何从 stream.Readable 同步读取行

Node.js how to synchronously read lines from stream.Readable

我正在通过 stdio 与子进程交互,并且 每次我向 childProcess.stdin 写入一些命令时,我都需要等待来自 childProcess.stdout 的一行。
像下面这样包装一个异步方法很容易写:

async function write(data){
    return new Promise(resolve=>{
        childProcess.stdin.write(data,()=>resolve());
    })
}

然而,当涉及到读取时,它变得相当困难,因为来自 stdout 的数据必须使用侦听器进行处理。我试过以下:

const LineReader = require("readline")
const reader = LineReader.createInterface(childProcess.stdout);
async function read(){
    return new Promise(resolve=>{
        reader.once("line",line=>resolve(line));
    })
}

但它总是returns第一行。
我知道我可以使用 setInterval 来实现这一点,而且我已经通过这种方式实现了该功能。但是很明显对性能有影响,所以现在想通过包装成异步方法来优化一下。
任何建议和解决方案将不胜感激!

好吧,我最终得到的结果与您正在尝试的非常相似。它做了代码中提到的一些假设,需要更完整的错误处理:

const cp = require('child_process');
const readline = require('readline');

const child = cp.spawn("node", ["./echo.js"]);
child.on('error', err => {
    console.log(err);
}).on('exit', () => {
    console.log("child exited");
});

const reader = readline.createInterface({ input: child.stdout });

// this will miss line events that occurred before this is called
// so this only really works if you know the output comes one line at a time
function nextLine() {
    return new Promise(resolve => {
        reader.once('line', resolve);
    });
}

// this does not check for stdin that is full and wants us to wait
// for a drain event
function write(str) {
    return new Promise(resolve => {
        let ready = child.stdin.write(str, resolve);
        if (!ready) {
            console.log("stream isn't ready yet");
        }
    });
}

async function sendCmd(cmd) {
    // get line reader event handler installed so there's no race condition
    // on missing the return event
    let p = nextLine();
    // send the command
    await write(cmd);
    return p;
}

// send a sequence of commands and get their results
async function run() {
    let result1 = await sendCmd("hi\n");
    console.log(`Got '${result1}'`);
    let result2 = await sendCmd("goodbye\n");
    console.log(`Got '${result2}'`);
    let result3 = await sendCmd("exit\n");
    console.log(`Got '${result3}'`);
}

run().then(() => {
    console.log("done");
}).catch(err => {
    console.log(err);
});

并且,出于测试目的,我 运行 使用此 echo 应用程序:

process.stdin.on("data", data => {
    let str = data.toString();
    let ready = process.stdout.write("return: " + str, () => {
        if (str.startsWith("exit")) {
            process.exit();
        }
    });
    if (!ready) {
        console.log("echo wasn't ready");
    }
});