如何以块而不是块的形式将字符串数据写入流

How to write string data to a stream in chunks, not a lump

我有一个 node.js 脚本,它必须在 STDIN 上接受 utf8 数据并在 STDOUT 上输出其他 utf8 数据 它旨在通过 shell 管道接受来自磁带测试框架 运行ner 的 TAP 字符串,并稍微修改它:

#!/usr/bin/env node
'use strict';

process.stdin.setDefaultEncoding('utf8');
process.stdout.setDefaultEncoding('utf8');
process.stdin.on('readable', () => {
  let chunk;
  while ((chunk = process.stdin.read()) !== null) {
    process.stdout.write('chunk: ' + chunk);
  }
});

process.stdin.on('end', () => {
  process.stdout.write('end\n');
});

当我 运行 对其进行磁带测试时 npm run test-unit test/unit/main.test.js | ./format.js 我得到(我将进一步将其称为“实时输出”):

chunk: 
> dummy@0.0.0 test-unit /path/dummy/zzz
> tape "test/unit/main.test.js"

chunk: TAP version 13
chunk: # test 1
chunk: # comment 1
chunk: ok 1 should be equal
chunk: 
1..1
chunk: # tests 1
# pass  1

# ok
chunk: 
end

所以你可以看到,数据被写入了 8 次,分为 8 个块。

我的问题是,如何在测试中模拟这种行为?

在测试中,我使用 spawn('./format.js') 生成了另一个进程,但我如何写入该进程的 STDIN,以便读取相同的数据需要 8 次,就像来自 tap 报告器一样。

我将原始的 tap 输出(没有 "chunk" 标记)拆分为一个字符串数组(相当于 实时输出 中的块)并尝试编写每个字符串在对 spawned.stdin 的单独写入调用中然后测试 format.js 的输出:

let spawned = spawn('./format.js');
let chunksOriginal = [
  // chunks here
];


spawned.stdout.on('readable', () => {
  console.log(spawned.stdout.read());
});
chunksOriginal.forEach((chunk, i) => {
  spawned.stdin.write(chunk);
});

我希望 console.log 输出与 实时输出相同的字符串 ,或者至少是它的第一个块,但我得到了:

chunk: 
> dummy@0.0.0 test-unit /path/dummy/zzz
> tape "test/unit/main.test.js"

TAP version 13
# test 1
# comment 1
ok 1 should be equal

1..1
# tests 1
# pass  1

# ok

end

如您所见,format.js 只读取了一次数据,上面有一个块标记。我试图在 write 调用之前在 forEach 循环中发出 "readable" 事件,这也没有帮助:

chunksOriginal.forEach((chunk, i) => {
  spawned.stdin.emit('readable');
  spawned.stdin.write(chunk);
});

我怀疑问题是我不理解 node.js 和 bash 中的 IPC 概念。 "live output" 中的数据可能是通过所谓的 node.js 缓冲区写入的。

我不是在寻求问题的确切解决方案,但如果有人提供,我将不胜感激。

只是概念层面的提示,我应该在哪里看什么文档来解决这个问题

我还尝试使用 setTimeout 来使写入过程异步,虽然我忘记在问题中提及这一点,但它也没有帮助:

chunksOriginal.forEach((chunk, i) => {
  setTimeout(() => {
    spawned.stdin.emit('readable');
    spawned.stdin.write(chunk);
  }, i);
});

然后我又试了一次,增加了延迟 i * 100 毫秒,成功了:

chunksOriginal.forEach((chunk, i) => {
  setTimeout(() => {
    spawned.stdin.write(chunk);
  }, i * 100);
});

这很有帮助,现在 format.js 从虚拟输入接收到与从实时输入接收到的块数量相同的块(尽管可能都需要一些调整,配置创建)。

另外值得注意的是,emit 调用是不必要的