lasso
Version:
Lasso.js is a build tool and runtime library for building and bundling all of the resources needed by a web application
132 lines (110 loc) • 3.4 kB
JavaScript
const Readable = require('stream').Readable;
const inherit = require('raptor-util/inherit');
function CombinedStream(options) {
CombinedStream.$super.call(this, options);
const streams = this.streams = [];
const combined = this;
let separator;
let curStream;
let i = -1;
let len;
let paused = false;
let reading = false;
if (options) {
separator = options.separator;
delete options.separator;
}
function onError(err) {
combined.emit('error', err);
}
function onData(chunk) {
if (combined.push(chunk) === false) {
paused = true;
curStream.pause();
}
}
let depth = 0;
/*
Node.js internally uses process.nextTick() during stream data
flow events. Node.js checks to make sure that process.nextTick()
is not called with too much recursion because this will starve
I/O event processing. The dependency streams may have read all of
their data so process.nextTick() could be called recursively more than
the allowed limit. The recommended approach for avoiding this limit
is to use setImmediate() to give the event loop a chance to handle
I/O events.
Recursive process.nextTick detected" from within stream code #6065
https://github.com/joyent/node/issues/6065
stream: readable _read blocking script execution #7401
https://github.com/joyent/node/issues/7401
*/
function cautiousNext() {
depth++;
if (depth > 100) {
depth = 0;
setImmediate(next);
} else {
next();
}
}
function next() {
if (curStream) {
combined.emit('endStream', {
stream: curStream,
index: i
});
}
if (++i >= len) {
// we're done
combined.push(null);
} else {
if (separator && curStream) {
combined.push(separator);
}
combined.curStream = curStream = streams[i];
combined.emit('beginStream', {
stream: curStream,
index: i
});
if (typeof curStream === 'string') {
onData(curStream);
cautiousNext();
} else {
curStream.on('end', cautiousNext);
curStream.on('error', onError);
curStream.on('data', onData);
// make sure the current stream is resumed
curStream.resume();
}
}
}
this._read = function() {
if (reading) {
if (paused) {
curStream.resume();
}
} else {
reading = true;
len = streams.length;
if (len === 0) {
combined.push(null);
} else {
cautiousNext();
}
}
};
}
CombinedStream.prototype.addStream = function(stream) {
this.streams.push(stream);
};
CombinedStream.prototype.getStream = function(index) {
return this.streams[index];
};
CombinedStream.prototype.getStreamCount = function(stream) {
return this.streams.length;
};
CombinedStream.prototype.forEachStream = function(fn) {
return this.streams.forEach(fn);
};
inherit(CombinedStream, Readable);
module.exports = CombinedStream;