使用Function.bind时节点转换流怪异

时间:2014-08-16 05:54:08

标签: javascript node.js stream

进入这个转换流行为,我无法解释。首先是设置:

var pass = new require('stream').PassThrough

var numbers = ['one:', 'two:', 'three:', 'four:', 'five:', 'six:', 'seven:', 'eight:', 'nine:', 'ten:']

pass.pipe(process.stdout)

好的,现在当我使用forEach写入流时,我得到以下预期的行为:

numbers.forEach(function(val) {
  pass.write(val)
})

# one:two:three:four:five:six:seven:eight:nine:ten:

但是!如果我以这种稍微不同的方式写入流,我会得到以下意外的行为:

numbers.forEach(pass.write.bind(pass))

# one:tthfoufivesix:seven:eight:nine:ten:

所以我的问题是,为什么不同的输出?我在这里错过了什么吗?

我正在运行v0.10.30

1 个答案:

答案 0 :(得分:3)

简答:

.forEach将多个参数传递给回调,因此当您直接传递回调时,您并不只是将val传递给回调,您也传递了数组索引和整个数组到.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)的签名时,如果它不是函数,则会忽略回调,因此您实际上正在执行.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])

由于您将编码作为数字而不是实际编码传递,因此使用编码值作为长度而不是编码进行调用,因此您将根据数组索引对字符串长度进行切片。