streams2: Do multipipe without always using forEach
The Array.forEach call is too expensive.
This commit is contained in:
parent
c2f62d496a
commit
2ff499c022
@ -62,7 +62,8 @@ function ReadableState(options, stream) {
|
|||||||
|
|
||||||
this.buffer = [];
|
this.buffer = [];
|
||||||
this.length = 0;
|
this.length = 0;
|
||||||
this.pipes = [];
|
this.pipes = null;
|
||||||
|
this.pipesCount = 0;
|
||||||
this.flowing = false;
|
this.flowing = false;
|
||||||
this.ended = false;
|
this.ended = false;
|
||||||
this.endEmitted = false;
|
this.endEmitted = false;
|
||||||
@ -282,7 +283,19 @@ Readable.prototype.pipe = function(dest, pipeOpts) {
|
|||||||
var state = this._readableState;
|
var state = this._readableState;
|
||||||
if (!pipeOpts)
|
if (!pipeOpts)
|
||||||
pipeOpts = {};
|
pipeOpts = {};
|
||||||
state.pipes.push(dest);
|
|
||||||
|
switch (state.pipesCount) {
|
||||||
|
case 0:
|
||||||
|
state.pipes = dest;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
state.pipes = [ state.pipes, dest ];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
state.pipes.push(dest);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
state.pipesCount += 1;
|
||||||
|
|
||||||
if ((!pipeOpts || pipeOpts.end !== false) &&
|
if ((!pipeOpts || pipeOpts.end !== false) &&
|
||||||
dest !== process.stdout &&
|
dest !== process.stdout &&
|
||||||
@ -320,15 +333,22 @@ function flow(src, pipeOpts) {
|
|||||||
flow(src, pipeOpts);
|
flow(src, pipeOpts);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (state.pipes.length &&
|
function write(dest, i, list) {
|
||||||
|
var written = dest.write(chunk);
|
||||||
|
if (false === written) {
|
||||||
|
needDrain++;
|
||||||
|
dest.once('drain', ondrain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (state.pipesCount &&
|
||||||
null !== (chunk = src.read(pipeOpts.chunkSize))) {
|
null !== (chunk = src.read(pipeOpts.chunkSize))) {
|
||||||
state.pipes.forEach(function(dest, i, list) {
|
|
||||||
var written = dest.write(chunk);
|
if (state.pipesCount === 1)
|
||||||
if (false === written) {
|
write(state.pipes, 0, null);
|
||||||
needDrain++;
|
else
|
||||||
dest.once('drain', ondrain);
|
state.pipes.forEach(write);
|
||||||
}
|
|
||||||
});
|
|
||||||
src.emit('data', chunk);
|
src.emit('data', chunk);
|
||||||
|
|
||||||
// if anyone needs a drain, then we have to wait for that.
|
// if anyone needs a drain, then we have to wait for that.
|
||||||
@ -340,7 +360,7 @@ function flow(src, pipeOpts) {
|
|||||||
// function, or in the while loop, then stop flowing.
|
// function, or in the while loop, then stop flowing.
|
||||||
//
|
//
|
||||||
// NB: This is a pretty rare edge case.
|
// NB: This is a pretty rare edge case.
|
||||||
if (state.pipes.length === 0) {
|
if (state.pipesCount === 0) {
|
||||||
state.flowing = false;
|
state.flowing = false;
|
||||||
|
|
||||||
// if there were data event listeners added, then switch to old mode.
|
// if there were data event listeners added, then switch to old mode.
|
||||||
@ -356,19 +376,55 @@ function flow(src, pipeOpts) {
|
|||||||
|
|
||||||
Readable.prototype.unpipe = function(dest) {
|
Readable.prototype.unpipe = function(dest) {
|
||||||
var state = this._readableState;
|
var state = this._readableState;
|
||||||
if (!dest) {
|
|
||||||
// remove all of them.
|
// if we're not piping anywhere, then do nothing.
|
||||||
state.pipes.forEach(function(dest, i, list) {
|
if (state.pipesCount === 0)
|
||||||
|
return this;
|
||||||
|
|
||||||
|
// just one destination. most common case.
|
||||||
|
if (state.pipesCount === 1) {
|
||||||
|
// passed in one, but it's not the right one.
|
||||||
|
if (dest && dest !== state.pipes)
|
||||||
|
return this;
|
||||||
|
|
||||||
|
if (!dest)
|
||||||
|
dest = state.pipes;
|
||||||
|
|
||||||
|
// got a match.
|
||||||
|
state.pipes = null;
|
||||||
|
state.pipesCount = 0;
|
||||||
|
if (dest)
|
||||||
dest.emit('unpipe', this);
|
dest.emit('unpipe', this);
|
||||||
}, this);
|
return this;
|
||||||
state.pipes.length = 0;
|
|
||||||
} else {
|
|
||||||
var i = state.pipes.indexOf(dest);
|
|
||||||
if (i !== -1) {
|
|
||||||
dest.emit('unpipe', this);
|
|
||||||
state.pipes.splice(i, 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// slow case. multiple pipe destinations.
|
||||||
|
|
||||||
|
if (!dest) {
|
||||||
|
// remove all.
|
||||||
|
var dests = state.pipes;
|
||||||
|
var len = state.pipesCount;
|
||||||
|
state.pipes = null;
|
||||||
|
state.pipesCount = 0;
|
||||||
|
|
||||||
|
for (var i = 0; i < len; i++)
|
||||||
|
dests[i].emit('unpipe', this);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to find the right one.
|
||||||
|
var i = state.pipes.indexOf(dest);
|
||||||
|
if (i === -1)
|
||||||
|
return this;
|
||||||
|
|
||||||
|
state.pipes.splice(i, 1);
|
||||||
|
state.pipesCount -= 1;
|
||||||
|
if (state.pipesCount === 1)
|
||||||
|
state.pipes = state.pipes[0];
|
||||||
|
|
||||||
|
dest.emit('unpipe', this);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -209,19 +209,27 @@ test('pipe', function(t) {
|
|||||||
w[0].on('write', function() {
|
w[0].on('write', function() {
|
||||||
if (--writes === 0) {
|
if (--writes === 0) {
|
||||||
r.unpipe();
|
r.unpipe();
|
||||||
|
t.equal(r._readableState.pipes, null);
|
||||||
w[0].end();
|
w[0].end();
|
||||||
r.pipe(w[1]);
|
r.pipe(w[1]);
|
||||||
|
t.equal(r._readableState.pipes, w[1]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var ended = 0;
|
var ended = 0;
|
||||||
|
|
||||||
|
var ended0 = false;
|
||||||
|
var ended1 = false;
|
||||||
w[0].on('end', function(results) {
|
w[0].on('end', function(results) {
|
||||||
|
t.equal(ended0, false);
|
||||||
|
ended0 = true;
|
||||||
ended++;
|
ended++;
|
||||||
t.same(results, expect[0]);
|
t.same(results, expect[0]);
|
||||||
});
|
});
|
||||||
|
|
||||||
w[1].on('end', function(results) {
|
w[1].on('end', function(results) {
|
||||||
|
t.equal(ended1, false);
|
||||||
|
ended1 = true;
|
||||||
ended++;
|
ended++;
|
||||||
t.equal(ended, 2);
|
t.equal(ended, 2);
|
||||||
t.same(results, expect[1]);
|
t.same(results, expect[1]);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user