如何在Node.js中向Deno子进程传输大JSON数据集?
Node.js向Deno子进程通过STDIN传输大JSON数据的正确实现方式
一、发送端(Node.js)的修正方案
你的核心问题之一是手动处理drain事件的逻辑有误,且未正确关闭STDIN告知Deno数据传输完成。推荐使用Node.js内置的stream/promises模块的pipeline方法,它会自动处理背压,无需手动监听drain:
const { spawn } = require('child_process'); const { pipeline } = require('stream/promises'); const { Readable } = require('stream'); const deno = spawn('deno', ['run', '--allow-all', '--unstable-bare-node-builtins', '--unstable-sloppy-imports', `--allow-read=${cwd}`, filename], { stdio: ['pipe', 'pipe', 'pipe'], cwd, env: { PATH: process.env.PATH, DENO_NO_PACKAGE_JSON: '1' } }); // 将大JSON转为可读流,避免一次性占用过多内存 const payloadStream = Readable.from(JSON.stringify(yourLargeDataset)); // 通过pipeline自动处理背压并完成写入 await pipeline(payloadStream, deno.stdin); // 关闭STDIN,告知Deno数据传输结束 deno.stdin.end();
如果坚持手动处理drain,需修正逻辑(Node.js的Writable.write返回布尔值而非Promise):
const writeChunk = (chunk: Buffer): Promise<void> => { return new Promise((resolve) => { const canContinue = deno.stdin.write(chunk); if (canContinue) { resolve(); } else { deno.stdin.once('drain', resolve); } }); }; // 使用示例: const payloadBuffer = Buffer.from(JSON.stringify(yourLargeDataset)); await writeChunk(payloadBuffer); deno.stdin.end();
二、接收端(Deno)的正确处理
Deno端必须读取STDIN的全部数据后再解析JSON,否则会因接收不完整导致解析失败:
// Deno端代码 const decoder = new TextDecoder(); // 读取STDIN所有数据直到EOF const rawData = await Deno.readAll(Deno.stdin); const jsonData = JSON.parse(decoder.decode(rawData)); // 处理数据 console.log(jsonData);
如果需要流式处理(超大规模JSON),需拼接所有chunk后再解析:
const decoder = new TextDecoder(); let buffer = ''; // 逐块读取STDIN流 for await (const chunk of Deno.stdin.readable) { buffer += decoder.decode(chunk); } const jsonData = JSON.parse(buffer);
三、解决ENOTTY: Not a Typewriter错误
该错误是因为Deno代码尝试将STDIN当作TTY终端处理(例如使用prompt()、readline模块等)。解决方式:
- 移除Deno代码中所有依赖TTY的交互逻辑,改为直接读取STDIN流。
- 确保Node.js启动Deno时的
stdio配置为['pipe', 'pipe', 'pipe'](你的代码已正确设置)。
四、额外优化建议
- 预发送数据长度:如果JSON体积极大,可先发送数据字节长度,Deno端先读取长度再精准读取对应字节数,避免流分割问题:
// Node.js端 const payload = JSON.stringify(yourLargeDataset); const lengthBuffer = Buffer.from(`${Buffer.byteLength(payload, 'utf8')}\n`); await pipeline(Readable.from([lengthBuffer, payload]), deno.stdin); deno.stdin.end();// Deno端 const decoder = new TextDecoder(); const lengthLine = await Deno.readTextLine(Deno.stdin); const dataLength = parseInt(lengthLine, 10); const rawData = new Uint8Array(dataLength); await Deno.readFull(Deno.stdin, rawData); const jsonData = JSON.parse(decoder.decode(rawData));
内容的提问来源于stack exchange,提问作者Jaron
相关产品推荐
相关产品推荐

