Skip to content

Commit 078188d

Browse files
mscdexMylesBorins
authored andcommitted
stream: avoid additional validation for Buffers
These changes result in ~50% improvement in the included benchmark. PR-URL: #10580 Reviewed-By: Сковорода Никита Андреевич <chalkerx@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 6486b97 commit 078188d

File tree

2 files changed

+40
-20
lines changed

2 files changed

+40
-20
lines changed

Diff for: benchmark/streams/writable-manywrites.js

+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+
}

Diff for: lib/_stream_writable.js

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

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

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

235-
if (chunk instanceof Buffer)
231+
if (isBuf)
236232
encoding = 'buffer';
237233
else if (!encoding)
238234
encoding = state.defaultEncoding;
@@ -242,9 +238,9 @@ Writable.prototype.write = function(chunk, encoding, cb) {
242238

243239
if (state.ended)
244240
writeAfterEnd(this, cb);
245-
else if (validChunk(this, state, chunk, cb)) {
241+
else if (isBuf || validChunk(this, state, chunk, cb)) {
246242
state.pendingcb++;
247-
ret = writeOrBuffer(this, state, chunk, encoding, cb);
243+
ret = writeOrBuffer(this, state, isBuf, chunk, encoding, cb);
248244
}
249245

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

303300
state.length += len;

0 commit comments

Comments
 (0)