先帖段简单的代码(t1.js)
process.stdin.on(‘readable’, function() { var buf = process.stdin.read(3); console.log(buf); process.stdin.read(0); });
然后在终端中运行命令①
(echo abc; sleep 1; echo def; sleep 1; echo ghi) | node t1.js
结果如下:
<Buffer 61 62 63> <Buffer 0a 64 65> <Buffer 66 0a 67> <Buffer 68 69 0a>
然后在终端中运行命令②
(echo abc; echo def; echo ghi) | node t1.js
结果如下:
<Buffer 61 62 63> <Buffer 0a 64 65>
我的问题是: 照成不同结果的原因是什么呢? 为什么不加 sleep 会出现丢失数据的情况? readable 事件为什么会退出?(readable的机制) 命令行管道符问题?
希望哪位高人能够解答
你可以用’data’事件处理下:
process.stdin.on('data', function(data) { console.log('data:' + data); });
不过这样read就会返回空
探索了一下楼主的问题
先看管道的问题:
$(echo abc; sleep 1; echo def; sleep 1; echo ghi) | xargs echo
$(echo abc; echo def; echo ghi) | xargs echo
输出结果一样,区别在于第一个要等三秒第二个直接打印了,所以传给node的buffer应该是一样的。
做了两个测试,readable被调用了几次(全局变量步增),是否跟var buf = process.stdin.read(3);
里面的3有关系,代码就不贴了;
两个测试结果: 楼主第一种情况handler被调用了4次,第二次被调用了2次。把3变为10后,第二种情况得到了一个长度为10的buffer+长度为2的buffer;
两个测试结论: 输出几次跟着两个有点关系,触发几次handler就会有几次输出,而每次read多少长度影响了接收到的buffer里的值是否能被全部读取(未读取的buffer被放在缓冲区)。
进一步,onsole.log(process.stdin);
,发现process.stdin._readableState.buffer
有点像缓冲区…
把代码改为:
var buffers = [];
var i = 0;
process.stdin.on('readable', function() {
buffers.push(process.stdin.read(3));
console.log(i++, buffers, process.stdin._readableState.buffer);
process.stdin.read(0);
});
结果1:
//(echo abc; sleep 1; echo def; sleep 1; echo ghi) | node t1.js
0 [ <Buffer 61 62 63> ] [ <Buffer 0a> ]
1 [ <Buffer 61 62 63>, <Buffer 0a 64 65> ] [ <Buffer 66 0a> ]
2 [ <Buffer 61 62 63>, <Buffer 0a 64 65>, <Buffer 66 0a 67> ] [ <Buffer 68 69 0a> ]
3 [ <Buffer 61 62 63>,
<Buffer 0a 64 65>,
<Buffer 66 0a 67>,
<Buffer 68 69 0a> ] []
结果2:
//(echo abc; echo def; echo ghi) | node t1.js
0 [ <Buffer 61 62 63> ] [ <Buffer 0a 64 65 66 0a 67 68 69 0a> ]
1 [ <Buffer 61 62 63>, <Buffer 0a 64 65> ] [ <Buffer 66 0a 67 68 69 0a> ]
结论
两次结果不一样是readable触发次数+read(N)中N的数量导致的。
而从结果来看 (echo abc; echo def; echo ghi)
只触发了一次readable,而断开前又会触发一次readable。
(echo abc; sleep 1; echo def; sleep 1; echo ghi)
则触发了 3+1 是 4 次。
readable 事件为什么会退出,是一个ctl+d…可以用 node t1.js
然后输入测试数据,最后 ctrl+d 退出,跟echo的效果一致
➜ ~ node t1
0 [ null ] []
abc
1 [ null, <Buffer 61 62 63> ] [ <Buffer 0a> ]
def
2 [ null, <Buffer 61 62 63>, <Buffer 0a 64 65> ] [ <Buffer 66 0a> ]
ghi
3 [ null, <Buffer 61 62 63>, <Buffer 0a 64 65>, <Buffer 66 0a 67> ] [ <Buffer 68 69 0a> ]
4 [ null,
<Buffer 61 62 63>,
<Buffer 0a 64 65>,
<Buffer 66 0a 67>,
<Buffer 68 69 0a> ] []
end
close
➜ ~
@albin3 非常感激您这么认真测试这个小程序。 我的理解如下: readable 事件由底层系统决定触发次数。 我们只能处理每次事件 drain 过来的数据。 这些数据可以一次全都 read 或 read(N)。 当 read(N) 时,N 小于本次 drain 过来数据的长度时,需要继续read(N),直到结束。 显然 read(0) 这个方法有时候并不可靠。
再您基础上我又做了如下修改:
var buffers = []; var i = 0; process.stdin.on(‘readable’, function() { var chunk; i++; while (null !== (chunk = process.stdin.read(3))) { buffers.push(chunk); console.log(i, buffers, process.stdin._readableState.buffer); } });
这次得到了我想要的效果,再次感谢您 @albin3