Skip to content

Commit f0a10ff

Browse files
mscdexitaloacasas
authored andcommitted
stream: avoid additional validation for Buffers
These changes result in ~50% improvement in the included benchmark. PR-URL: nodejs#10580 Reviewed-By: Сковорода Никита Андреевич <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 1f52eca commit f0a10ff

File tree

2 files changed

+40
-20
lines changed

2 files changed

+40
-20
lines changed
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const Writable = require('stream').Writable;
5+
6+
const bench = common.createBenchmark(main, {
7+
n: [2e6]
8+
});
9+
10+
function main(conf) {
11+
const n = +conf.n;
12+
const b = Buffer.allocUnsafe(1024);
13+
const s = new Writable();
14+
s._write = function(chunk, encoding, cb) {
15+
cb();
16+
};
17+
18+
bench.start();
19+
for (var k = 0; k < n; ++k) {
20+
s.write(b);
21+
}
22+
bench.end(n);
23+
}

lib/_stream_writable.js

+17-20
Original file line numberDiff line numberDiff line change
@@ -194,23 +194,18 @@ function writeAfterEnd(stream, cb) {
194194
process.nextTick(cb, er);
195195
}
196196

197-
// If we get something that is not a buffer, string, null, or undefined,
198-
// and we're not in objectMode, then that's an error.
199-
// Otherwise stream chunks are all considered to be of length=1, and the
200-
// watermarks determine how many objects to keep in the buffer, rather than
201-
// how many bytes or characters.
197+
// Checks that a user-supplied chunk is valid, especially for the particular
198+
// mode the stream is in. Currently this means that `null` is never accepted
199+
// and undefined/non-string values are only allowed in object mode.
202200
function validChunk(stream, state, chunk, cb) {
203201
var valid = true;
204202
var er = false;
205-
// Always throw error if a null is written
206-
// if we are not in object mode then throw
207-
// if it is not a buffer, string, or undefined.
203+
208204
if (chunk === null) {
209205
er = new TypeError('May not write null values to stream');
210-
} else if (!(chunk instanceof Buffer) &&
211-
typeof chunk !== 'string' &&
212-
chunk !== undefined &&
213-
!state.objectMode) {
206+
} else if (typeof chunk !== 'string' &&
207+
chunk !== undefined &&
208+
!state.objectMode) {
214209
er = new TypeError('Invalid non-string/buffer chunk');
215210
}
216211
if (er) {
@@ -224,13 +219,14 @@ function validChunk(stream, state, chunk, cb) {
224219
Writable.prototype.write = function(chunk, encoding, cb) {
225220
var state = this._writableState;
226221
var ret = false;
222+
var isBuf = (chunk instanceof Buffer);
227223

228224
if (typeof encoding === 'function') {
229225
cb = encoding;
230226
encoding = null;
231227
}
232228

233-
if (chunk instanceof Buffer)
229+
if (isBuf)
234230
encoding = 'buffer';
235231
else if (!encoding)
236232
encoding = state.defaultEncoding;
@@ -240,9 +236,9 @@ Writable.prototype.write = function(chunk, encoding, cb) {
240236

241237
if (state.ended)
242238
writeAfterEnd(this, cb);
243-
else if (validChunk(this, state, chunk, cb)) {
239+
else if (isBuf || validChunk(this, state, chunk, cb)) {
244240
state.pendingcb++;
245-
ret = writeOrBuffer(this, state, chunk, encoding, cb);
241+
ret = writeOrBuffer(this, state, isBuf, chunk, encoding, cb);
246242
}
247243

248244
return ret;
@@ -291,11 +287,12 @@ function decodeChunk(state, chunk, encoding) {
291287
// if we're already writing something, then just put this
292288
// in the queue, and wait our turn. Otherwise, call _write
293289
// If we return false, then we need a drain event, so set that flag.
294-
function writeOrBuffer(stream, state, chunk, encoding, cb) {
295-
chunk = decodeChunk(state, chunk, encoding);
296-
297-
if (chunk instanceof Buffer)
298-
encoding = 'buffer';
290+
function writeOrBuffer(stream, state, isBuf, chunk, encoding, cb) {
291+
if (!isBuf) {
292+
chunk = decodeChunk(state, chunk, encoding);
293+
if (chunk instanceof Buffer)
294+
encoding = 'buffer';
295+
}
299296
var len = state.objectMode ? 1 : chunk.length;
300297

301298
state.length += len;

0 commit comments

Comments
 (0)