In Node.js, when you work with Readable and Writable streams, string values are decoded into Buffers by default. You can override this by initializing a stream with "decodeStrings: false"; but, if you omit this configuration, it defaults to true. But, what happens if a stream is running in "Object Mode"? Are strings still decoded into buffers? It turns out, they are not. A string, passing through an "Object Mode" stream, remains a string.
To test this, I created a simple Readable and Writable subclass that runs in Object Mode. Then, I read one chunk from the readable stream, logged it out, and then wrote it to the writable stream:
// Require our code node modules.
var stream = require( "stream" );
var util = require( "util" );
// ----------------------------------------------------------------------------------- //
// ----------------------------------------------------------------------------------- //
// I am a simple readable stream in Object Mode that pushes the same message onto the
// internal buffer over and over again.
// --
// CAUTION: Do not use me in "flow" mode as I will never end - I'm the juggernaut!
function ReadableObjects() {
stream.Readable.call(
this,
{
objectMode: true,
decodeStrings: true // Attempting to force Buffers.
}
);
}
util.inherits( ReadableObjects, stream.Readable );
// I push the same message onto the internal buffer.
ReadableObjects.prototype._read = function( _sizeIsIgnoredInObjectMode ) {
this.push( "Shut up... Just shut up... You had me at 'hello'." );
}
// ----------------------------------------------------------------------------------- //
// ----------------------------------------------------------------------------------- //
// I am simple writable stream in Object Mode that logs-out the chunks it receives.
function WritableObjects() {
stream.Writable.call(
this,
{
objectMode: true,
decodeStrings: true // Attempting to force Buffers.
}
);
}
util.inherits( WritableObjects, stream.Writable );
// I log the chunk and chunk data type to the console.
WritableObjects.prototype._write = function( chunk, encoding, doneWriting ) {
console.log( "In _write:", chunk );
console.log( "Encoding:", encoding );
doneWriting();
};
// ----------------------------------------------------------------------------------- //
// ----------------------------------------------------------------------------------- //
// Create our testing stream instances (in Object Mode).
var readable = new ReadableObjects();
var writable = new WritableObjects();
// Since the readable stream will never end, we only want to test this on one data
// event in NON-FLOW mode. As such, we have to wait for a readable event and then
// read one chunk and explicitly pass it the writable stream.
readable.once(
"readable",
function handleReadable() {
var chunk = readable.read();
console.log( "In readable:", chunk );
// NOTE: Forcing this to a string to see if it gets decoded into a buffer.
writable.write( chunk.toString() );
}
);
As you can see, for good measure, I'm even including "decodeStrings: true" in an attempt to force the string decoding. But, when we run this code, we get the following terminal output:
ben$ node test.js
In readable: Shut up... Just shut up... You had me at 'hello'.
In _write: Shut up... Just shut up... You had me at 'hello'.
Encoding: utf8
As you can see, the string value remains a string value throughout the stream life cycle, when the stream is running in Objet Mode.
As a side note, if the original Readable stream had pushed a Buffer instance, instead of a String instance, then the value would have remained a Buffer throughout the stream life cycle. It's not that values are being converted to strings in Object Mode - it's that values aren't being converted at all: value in becomes value out, no transformation.
Reader Comments