使用Function.bind时节点转换stream怪癖
进入这个转换stream的行为,我不能解释。 首先设置:
var pass = new require('stream').PassThrough var numbers = ['one:', 'two:', 'three:', 'four:', 'five:', 'six:', 'seven:', 'eight:', 'nine:', 'ten:'] pass.pipe(process.stdout)
好的,现在当我使用forEach
写入stream时,我得到以下预期的行为:
numbers.forEach(function(val) { pass.write(val) }) # one:two:three:four:five:six:seven:eight:nine:ten:
但! 如果我以这样稍微不同的方式写入stream,我会得到以下意外的行为:
numbers.forEach(pass.write.bind(pass)) # one:tthfoufivesix:seven:eight:nine:ten:
所以我的问题是,为什么不同的产出? 我在这里错过了什么吗?
我正在运行v0.10.30
简短的回答:
.forEach
将多个parameter passing给callback函数,因此直接传递callback函数时,不仅仅是将val
传递给callback函数,还会将数组索引和整个数组传递给.write
。
很长的回答:
你的等价比较是错误的:
numbers.forEach(pass.write.bind(pass));
是不一样的
numbers.forEach(function(val) { pass.write(val) });
这相当于这样的:
numbers.forEach(function() { pass.write.apply(pass, arguments); });
或者更具体地说:
numbers.forEach(function(val, index, array) { pass.write(val, index /* encoding */, array /* cb */); });
当你查看.write(chunk, encoding, cb)
的签名时,如果它不是一个函数,那么callback将被忽略,所以你基本上在做.write(val, index)
。 疯狂的输出是由于这些值在写入之前被传入Buffer
,所以你实质上是这样调用的:
numbers.forEach(function(val, index, array) { pass.write(new Buffer(val, index /* encoding */)); });
分解成这样的东西:
numbers.forEach(function(val, index, array) { var b = new Buffer(...); b.write(val, index /* encoding */); pass.write(b); });
这就是魔术发生的地方。 Buffer.prototype.write
的签名是
.write(string, [offset], [length], [encoding])
由于您将编码作为数字而不是实际编码传递给编码,因此使用编码值作为长度而不是编码的调用,因此您正在根据数组索引切分string长度。