将 stdout 和 stderr 合并到单个 node.js 流中

问题描述 投票:0回答:1

我想将子进程的 stdout 和 stderr 组合成一个单一的中间流,然后我可以使用它并进行处理。

这可以通过标准 API 实现吗?

(我意识到交错两个流有一些微妙之处,我需要它们只在行结尾上交错才能工作。即,向 stdout 或 stderr 写入一行应该是一个原子操作)。

node.js stream stdout stderr io.js
1个回答
0
投票

这应该按预期工作:

// This custom stream merges stdout and stderr.
    // Instead of concatenating the two streams, it keeps their interleaving.
    const stdoutStderrInterleavedStream = (
        stdout: ReadableStreamDefaultReader<Uint8Array>,
        stderr: ReadableStreamDefaultReader<Uint8Array>
    ) =>
        new ReadableStream({
            start(controller) {
                // These sentinel values are used to know if both stream have been stopped.
                let stdoutDone = false
                let stderrDone = false

                type SentinelFunctions = {
                    getDone: () => boolean
                    setDone: () => void
                }

                // stdout will check if stderr is done
                const sentinelStdout: SentinelFunctions = {
                    getDone: () => stderrDone,
                    setDone: () => (stdoutDone = true),
                }
                const sentinelStderr: SentinelFunctions = {
                    getDone: () => stdoutDone,
                    setDone: () => (stderrDone = true),
                }

                const push = () => {
                    const onData =
                        ({ getDone, setDone }: SentinelFunctions) =>
                        ({ done, value }: ReadableStreamDefaultReadResult<Uint8Array>) => {
                            if (done) {
                                setDone()
                                if (getDone()) {
                                    controller.close()
                                }
                                return
                            }
                            controller.enqueue(value)
                            push()
                        }

                    stdout.read().then(onData(sentinelStdout))
                    stderr.read().then(onData(sentinelStderr))
                }
                push()
            },
        })

使用示例:

const stream = stdoutStderrInterleavedStream(
        myDenoProcess.stdout.getReader(),
        myDenoProcess.stderr.getReader()
    )
        .pipeThrough(new TextDecoderStream())
        .pipeThrough(new TextLineStream())

const output = await Array.fromAsync(stream)
console.log(output)
© www.soinside.com 2019 - 2024. All rights reserved.