stream: avoid additional validation for Buffers
These changes result in ~50% improvement in the included benchmark. PR-URL: https://github.com/nodejs/node/pull/10580 Reviewed-By: Сковорода Никита Андреевич <chalkerx@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
parent
aab1dd6ff4
commit
0a937280d8
23
benchmark/streams/writable-manywrites.js
Normal file
23
benchmark/streams/writable-manywrites.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const common = require('../common');
|
||||||
|
const Writable = require('stream').Writable;
|
||||||
|
|
||||||
|
const bench = common.createBenchmark(main, {
|
||||||
|
n: [2e6]
|
||||||
|
});
|
||||||
|
|
||||||
|
function main(conf) {
|
||||||
|
const n = +conf.n;
|
||||||
|
const b = Buffer.allocUnsafe(1024);
|
||||||
|
const s = new Writable();
|
||||||
|
s._write = function(chunk, encoding, cb) {
|
||||||
|
cb();
|
||||||
|
};
|
||||||
|
|
||||||
|
bench.start();
|
||||||
|
for (var k = 0; k < n; ++k) {
|
||||||
|
s.write(b);
|
||||||
|
}
|
||||||
|
bench.end(n);
|
||||||
|
}
|
@ -194,23 +194,18 @@ function writeAfterEnd(stream, cb) {
|
|||||||
process.nextTick(cb, er);
|
process.nextTick(cb, er);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we get something that is not a buffer, string, null, or undefined,
|
// Checks that a user-supplied chunk is valid, especially for the particular
|
||||||
// and we're not in objectMode, then that's an error.
|
// mode the stream is in. Currently this means that `null` is never accepted
|
||||||
// Otherwise stream chunks are all considered to be of length=1, and the
|
// and undefined/non-string values are only allowed in object mode.
|
||||||
// watermarks determine how many objects to keep in the buffer, rather than
|
|
||||||
// how many bytes or characters.
|
|
||||||
function validChunk(stream, state, chunk, cb) {
|
function validChunk(stream, state, chunk, cb) {
|
||||||
var valid = true;
|
var valid = true;
|
||||||
var er = false;
|
var er = false;
|
||||||
// Always throw error if a null is written
|
|
||||||
// if we are not in object mode then throw
|
|
||||||
// if it is not a buffer, string, or undefined.
|
|
||||||
if (chunk === null) {
|
if (chunk === null) {
|
||||||
er = new TypeError('May not write null values to stream');
|
er = new TypeError('May not write null values to stream');
|
||||||
} else if (!(chunk instanceof Buffer) &&
|
} else if (typeof chunk !== 'string' &&
|
||||||
typeof chunk !== 'string' &&
|
chunk !== undefined &&
|
||||||
chunk !== undefined &&
|
!state.objectMode) {
|
||||||
!state.objectMode) {
|
|
||||||
er = new TypeError('Invalid non-string/buffer chunk');
|
er = new TypeError('Invalid non-string/buffer chunk');
|
||||||
}
|
}
|
||||||
if (er) {
|
if (er) {
|
||||||
@ -224,13 +219,14 @@ function validChunk(stream, state, chunk, cb) {
|
|||||||
Writable.prototype.write = function(chunk, encoding, cb) {
|
Writable.prototype.write = function(chunk, encoding, cb) {
|
||||||
var state = this._writableState;
|
var state = this._writableState;
|
||||||
var ret = false;
|
var ret = false;
|
||||||
|
var isBuf = (chunk instanceof Buffer);
|
||||||
|
|
||||||
if (typeof encoding === 'function') {
|
if (typeof encoding === 'function') {
|
||||||
cb = encoding;
|
cb = encoding;
|
||||||
encoding = null;
|
encoding = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chunk instanceof Buffer)
|
if (isBuf)
|
||||||
encoding = 'buffer';
|
encoding = 'buffer';
|
||||||
else if (!encoding)
|
else if (!encoding)
|
||||||
encoding = state.defaultEncoding;
|
encoding = state.defaultEncoding;
|
||||||
@ -240,9 +236,9 @@ Writable.prototype.write = function(chunk, encoding, cb) {
|
|||||||
|
|
||||||
if (state.ended)
|
if (state.ended)
|
||||||
writeAfterEnd(this, cb);
|
writeAfterEnd(this, cb);
|
||||||
else if (validChunk(this, state, chunk, cb)) {
|
else if (isBuf || validChunk(this, state, chunk, cb)) {
|
||||||
state.pendingcb++;
|
state.pendingcb++;
|
||||||
ret = writeOrBuffer(this, state, chunk, encoding, cb);
|
ret = writeOrBuffer(this, state, isBuf, chunk, encoding, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -291,11 +287,12 @@ function decodeChunk(state, chunk, encoding) {
|
|||||||
// if we're already writing something, then just put this
|
// if we're already writing something, then just put this
|
||||||
// in the queue, and wait our turn. Otherwise, call _write
|
// in the queue, and wait our turn. Otherwise, call _write
|
||||||
// If we return false, then we need a drain event, so set that flag.
|
// If we return false, then we need a drain event, so set that flag.
|
||||||
function writeOrBuffer(stream, state, chunk, encoding, cb) {
|
function writeOrBuffer(stream, state, isBuf, chunk, encoding, cb) {
|
||||||
chunk = decodeChunk(state, chunk, encoding);
|
if (!isBuf) {
|
||||||
|
chunk = decodeChunk(state, chunk, encoding);
|
||||||
if (chunk instanceof Buffer)
|
if (chunk instanceof Buffer)
|
||||||
encoding = 'buffer';
|
encoding = 'buffer';
|
||||||
|
}
|
||||||
var len = state.objectMode ? 1 : chunk.length;
|
var len = state.objectMode ? 1 : chunk.length;
|
||||||
|
|
||||||
state.length += len;
|
state.length += len;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user